k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/controller/volume/attachdetach/cache/actual_state_of_world_test.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes Authors.
     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 cache
    18  
    19  import (
    20  	"testing"
    21  	"time"
    22  
    23  	v1 "k8s.io/api/core/v1"
    24  	"k8s.io/apimachinery/pkg/types"
    25  	"k8s.io/klog/v2/ktesting"
    26  	controllervolumetesting "k8s.io/kubernetes/pkg/controller/volume/attachdetach/testing"
    27  	volumetesting "k8s.io/kubernetes/pkg/volume/testing"
    28  	volumeutil "k8s.io/kubernetes/pkg/volume/util"
    29  )
    30  
    31  // Calls AddVolumeNode() once with attached set to true.
    32  // Verifies a single volume/node entry exists.
    33  func Test_AddVolumeNode_Positive_NewVolumeNewNode(t *testing.T) {
    34  	// Arrange
    35  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
    36  	asw := NewActualStateOfWorld(volumePluginMgr)
    37  	volumeName := v1.UniqueVolumeName("volume-name")
    38  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
    39  
    40  	nodeName := types.NodeName("node-name")
    41  	devicePath := "fake/device/path"
    42  
    43  	// Act
    44  	logger, _ := ktesting.NewTestContext(t)
    45  	generatedVolumeName, err := asw.AddVolumeNode(logger, volumeName, volumeSpec, nodeName, devicePath, true)
    46  
    47  	// Assert
    48  	if err != nil {
    49  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", err)
    50  	}
    51  
    52  	volumeNodeComboState := asw.GetAttachState(generatedVolumeName, nodeName)
    53  	if volumeNodeComboState != AttachStateAttached {
    54  		t.Fatalf("%q/%q volume/node combo is marked %q; expected 'Attached'.", generatedVolumeName, nodeName, volumeNodeComboState)
    55  	}
    56  
    57  	attachedVolumes := asw.GetAttachedVolumes()
    58  	if len(attachedVolumes) != 1 {
    59  		t.Fatalf("len(attachedVolumes) Expected: <1> Actual: <%v>", len(attachedVolumes))
    60  	}
    61  
    62  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName, string(volumeName), nodeName, devicePath, true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
    63  }
    64  
    65  // Calls AddVolumeNode() once with attached set to false.
    66  // Verifies a single volume/node entry exists.
    67  // Then calls AddVolumeNode() with attached set to true
    68  // Verifies volume is attached to the node according to asw.
    69  func Test_AddVolumeNode_Positive_NewVolumeNewNodeWithFalseAttached(t *testing.T) {
    70  	// Arrange
    71  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
    72  	asw := NewActualStateOfWorld(volumePluginMgr)
    73  	volumeName := v1.UniqueVolumeName("volume-name")
    74  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
    75  
    76  	nodeName := types.NodeName("node-name")
    77  	devicePath := "fake/device/path"
    78  
    79  	// Act
    80  	logger, _ := ktesting.NewTestContext(t)
    81  	generatedVolumeName, err := asw.AddVolumeNode(logger, volumeName, volumeSpec, nodeName, devicePath, false)
    82  
    83  	// Assert
    84  	if err != nil {
    85  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", err)
    86  	}
    87  
    88  	volumeNodeComboState := asw.GetAttachState(generatedVolumeName, nodeName)
    89  	if volumeNodeComboState != AttachStateUncertain {
    90  		t.Fatalf("%q/%q volume/node combo is marked %q, expected 'Uncertain'.", generatedVolumeName, nodeName, volumeNodeComboState)
    91  	}
    92  
    93  	allVolumes := asw.GetAttachedVolumes()
    94  	if len(allVolumes) != 1 {
    95  		t.Fatalf("len(attachedVolumes) Expected: <1> Actual: <%v>", len(allVolumes))
    96  	}
    97  	verifyAttachedVolume(t, allVolumes, generatedVolumeName, string(volumeName), nodeName, devicePath, true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
    98  
    99  	reportAsAttachedVolumesMap := asw.GetVolumesToReportAttached(logger)
   100  	_, exists := reportAsAttachedVolumesMap[nodeName]
   101  	if exists {
   102  		t.Fatalf("AddVolumeNode_Positive_NewVolumeNewNodeWithFalseAttached failed. Actual: <node %q exist> Expect: <node does not exist in the reportedAsAttached map", nodeName)
   103  	}
   104  
   105  	volumesForNode := asw.GetAttachedVolumesForNode(nodeName)
   106  	if len(volumesForNode) != 1 {
   107  		t.Fatalf("len(attachedVolumes) Expected: <1> Actual: <%v>", len(volumesForNode))
   108  	}
   109  	verifyAttachedVolume(t, volumesForNode, generatedVolumeName, string(volumeName), nodeName, devicePath, true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
   110  
   111  	attachedVolumesMap := asw.GetAttachedVolumesPerNode()
   112  	_, exists = attachedVolumesMap[nodeName]
   113  	if exists {
   114  		t.Fatalf("AddVolumeNode_Positive_NewVolumeNewNodeWithFalseAttached failed. Actual: <node %q exist> Expect: <node does not exist in the reportedAsAttached map", nodeName)
   115  	}
   116  
   117  	nodes := asw.GetNodesForAttachedVolume(volumeName)
   118  	if len(nodes) > 0 {
   119  		t.Fatalf("AddVolumeNode_Positive_NewVolumeNewNodeWithFalseAttached failed. Expect no nodes returned.")
   120  	}
   121  
   122  	// Add the volume to the node second time with attached set to true
   123  	generatedVolumeName2, add2Err := asw.AddVolumeNode(logger, volumeName, volumeSpec, nodeName, devicePath, true)
   124  
   125  	// Assert
   126  	if add2Err != nil {
   127  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", add2Err)
   128  	}
   129  
   130  	if generatedVolumeName != generatedVolumeName2 {
   131  		t.Fatalf(
   132  			"Generated volume names for the same volume should be the same but they are not: %q and %q",
   133  			generatedVolumeName,
   134  			generatedVolumeName2)
   135  	}
   136  
   137  	volumeNodeComboState = asw.GetAttachState(generatedVolumeName, nodeName)
   138  	if volumeNodeComboState != AttachStateAttached {
   139  		t.Fatalf("%q/%q volume/node combo is marked %q; expected 'Attached'.", generatedVolumeName, nodeName, volumeNodeComboState)
   140  	}
   141  
   142  	attachedVolumes := asw.GetAttachedVolumes()
   143  	if len(attachedVolumes) != 1 {
   144  		t.Fatalf("len(attachedVolumes) Expected: <1> Actual: <%v>", len(attachedVolumes))
   145  	}
   146  
   147  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName, string(volumeName), nodeName, devicePath, true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
   148  
   149  	nodes = asw.GetNodesForAttachedVolume(volumeName)
   150  	if len(nodes) != 1 {
   151  		t.Fatalf("AddVolumeNode_Positive_NewVolumeNewNodeWithFalseAttached failed. Expect one node returned.")
   152  	}
   153  	if nodes[0] != nodeName {
   154  		t.Fatalf("AddVolumeNode_Positive_NewVolumeNewNodeWithFalseAttached failed. Expect node %v, Actual node %v", nodeName, nodes[0])
   155  	}
   156  
   157  	attachedVolumesMap = asw.GetAttachedVolumesPerNode()
   158  	_, exists = attachedVolumesMap[nodeName]
   159  	if !exists {
   160  		t.Fatalf("AddVolumeNode_Positive_NewVolumeNewNodeWithFalseAttached failed. Actual: <node %q does not exist> Expect: <node does exist in the reportedAsAttached map", nodeName)
   161  	}
   162  
   163  }
   164  
   165  // Calls AddVolumeNode() once with attached set to false.
   166  // Verifies a single volume/node entry exists.
   167  // Then calls AddVolumeNode() to attach the volume to a different node with attached set to true
   168  // Verifies volume is attached to the node according to asw.
   169  func Test_AddVolumeNode_Positive_NewVolumeTwoNodesWithFalseAttached(t *testing.T) {
   170  	// Arrange
   171  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
   172  	asw := NewActualStateOfWorld(volumePluginMgr)
   173  	volumeName := v1.UniqueVolumeName("volume-name")
   174  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   175  
   176  	node1Name := types.NodeName("node1-name")
   177  	node2Name := types.NodeName("node2-name")
   178  	devicePath := "fake/device/path"
   179  
   180  	// Act
   181  	logger, _ := ktesting.NewTestContext(t)
   182  	generatedVolumeName, err := asw.AddVolumeNode(logger, volumeName, volumeSpec, node1Name, devicePath, false)
   183  
   184  	// Assert
   185  	if err != nil {
   186  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", err)
   187  	}
   188  
   189  	volumeNodeComboState := asw.GetAttachState(generatedVolumeName, node1Name)
   190  	if volumeNodeComboState != AttachStateUncertain {
   191  		t.Fatalf("%q/%q volume/node combo is marked %q, expected 'Uncertain'.", generatedVolumeName, node1Name, volumeNodeComboState)
   192  	}
   193  
   194  	generatedVolumeName2, add2Err := asw.AddVolumeNode(logger, volumeName, volumeSpec, node2Name, devicePath, true)
   195  
   196  	// Assert
   197  	if add2Err != nil {
   198  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", add2Err)
   199  	}
   200  
   201  	if generatedVolumeName != generatedVolumeName2 {
   202  		t.Fatalf(
   203  			"Generated volume names for the same volume should be the same but they are not: %q and %q",
   204  			generatedVolumeName,
   205  			generatedVolumeName2)
   206  	}
   207  
   208  	volumeNodeComboState = asw.GetAttachState(generatedVolumeName, node2Name)
   209  	if volumeNodeComboState != AttachStateAttached {
   210  		t.Fatalf("%q/%q volume/node combo is marked %q; expected 'Attached'.", generatedVolumeName, node2Name, volumeNodeComboState)
   211  	}
   212  
   213  	attachedVolumes := asw.GetAttachedVolumes()
   214  	if len(attachedVolumes) != 2 {
   215  		t.Fatalf("len(attachedVolumes) Expected: <2> Actual: <%v>", len(attachedVolumes))
   216  	}
   217  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName, string(volumeName), node1Name, devicePath, true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
   218  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName, string(volumeName), node2Name, devicePath, true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
   219  
   220  	volumesForNode := asw.GetAttachedVolumesForNode(node2Name)
   221  	if len(volumesForNode) != 1 {
   222  		t.Fatalf("len(attachedVolumes) Expected: <2> Actual: <%v>", len(volumesForNode))
   223  	}
   224  	verifyAttachedVolume(t, volumesForNode, generatedVolumeName, string(volumeName), node2Name, devicePath, true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
   225  
   226  	attachedVolumesMap := asw.GetAttachedVolumesPerNode()
   227  	attachedVolumesPerNode, exists := attachedVolumesMap[node2Name]
   228  	if !exists || len(attachedVolumesPerNode) != 1 {
   229  		t.Fatalf("AddVolumeNode_Positive_NewVolumeTwoNodesWithFalseAttached failed. Actual: <node %q does not exist> Expect: <node does exist in the reportedAsAttached map", node2Name)
   230  	}
   231  
   232  	nodes := asw.GetNodesForAttachedVolume(volumeName)
   233  	if len(nodes) != 1 {
   234  		t.Fatalf("AddVolumeNode_Positive_NewVolumeNewNodeWithFalseAttached failed. Expect one node returned.")
   235  	}
   236  
   237  	reportAsAttachedVolumesMap := asw.GetVolumesToReportAttached(logger)
   238  	reportedVolumes, exists := reportAsAttachedVolumesMap[node2Name]
   239  	if !exists || len(reportedVolumes) != 1 {
   240  		t.Fatalf("AddVolumeNode_Positive_NewVolumeNewNodeWithFalseAttached failed. Actual: <node %q exist> Expect: <node does not exist in the reportedAsAttached map", node2Name)
   241  	}
   242  }
   243  
   244  // Calls AddVolumeNode() twice. Second time use a different node name.
   245  // Verifies two volume/node entries exist with the same volumeSpec.
   246  func Test_AddVolumeNode_Positive_ExistingVolumeNewNode(t *testing.T) {
   247  	// Arrange
   248  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
   249  	asw := NewActualStateOfWorld(volumePluginMgr)
   250  	volumeName := v1.UniqueVolumeName("volume-name")
   251  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   252  	node1Name := types.NodeName("node1-name")
   253  	node2Name := types.NodeName("node2-name")
   254  	devicePath := "fake/device/path"
   255  
   256  	// Act
   257  	logger, _ := ktesting.NewTestContext(t)
   258  	generatedVolumeName1, add1Err := asw.AddVolumeNode(logger, volumeName, volumeSpec, node1Name, devicePath, true)
   259  	generatedVolumeName2, add2Err := asw.AddVolumeNode(logger, volumeName, volumeSpec, node2Name, devicePath, true)
   260  
   261  	// Assert
   262  	if add1Err != nil {
   263  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", add1Err)
   264  	}
   265  	if add2Err != nil {
   266  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", add2Err)
   267  	}
   268  
   269  	if generatedVolumeName1 != generatedVolumeName2 {
   270  		t.Fatalf(
   271  			"Generated volume names for the same volume should be the same but they are not: %q and %q",
   272  			generatedVolumeName1,
   273  			generatedVolumeName2)
   274  	}
   275  
   276  	volumeNode1ComboState := asw.GetAttachState(generatedVolumeName1, node1Name)
   277  	if volumeNode1ComboState != AttachStateAttached {
   278  		t.Fatalf("%q/%q volume/node combo is marked %q; expected 'Attached'.", generatedVolumeName1, node1Name, volumeNode1ComboState)
   279  	}
   280  
   281  	volumeNode2ComboState := asw.GetAttachState(generatedVolumeName1, node2Name)
   282  	if volumeNode2ComboState != AttachStateAttached {
   283  		t.Fatalf("%q/%q volume/node combo is marked %q; expected 'Attached'.", generatedVolumeName1, node2Name, volumeNode2ComboState)
   284  	}
   285  
   286  	attachedVolumes := asw.GetAttachedVolumes()
   287  	if len(attachedVolumes) != 2 {
   288  		t.Fatalf("len(attachedVolumes) Expected: <2> Actual: <%v>", len(attachedVolumes))
   289  	}
   290  
   291  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName1, string(volumeName), node1Name, devicePath, true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
   292  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName1, string(volumeName), node2Name, devicePath, true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
   293  }
   294  
   295  // Calls AddVolumeNode() twice. Uses the same volume and node both times.
   296  // Verifies a single volume/node entry exists.
   297  func Test_AddVolumeNode_Positive_ExistingVolumeExistingNode(t *testing.T) {
   298  	// Arrange
   299  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
   300  	asw := NewActualStateOfWorld(volumePluginMgr)
   301  	volumeName := v1.UniqueVolumeName("volume-name")
   302  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   303  	nodeName := types.NodeName("node-name")
   304  	devicePath := "fake/device/path"
   305  
   306  	// Act
   307  	logger, _ := ktesting.NewTestContext(t)
   308  	generatedVolumeName1, add1Err := asw.AddVolumeNode(logger, volumeName, volumeSpec, nodeName, devicePath, true)
   309  	generatedVolumeName2, add2Err := asw.AddVolumeNode(logger, volumeName, volumeSpec, nodeName, devicePath, true)
   310  
   311  	// Assert
   312  	if add1Err != nil {
   313  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", add1Err)
   314  	}
   315  	if add2Err != nil {
   316  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", add2Err)
   317  	}
   318  
   319  	if generatedVolumeName1 != generatedVolumeName2 {
   320  		t.Fatalf(
   321  			"Generated volume names for the same volume should be the same but they are not: %q and %q",
   322  			generatedVolumeName1,
   323  			generatedVolumeName2)
   324  	}
   325  
   326  	volumeNodeComboState := asw.GetAttachState(generatedVolumeName1, nodeName)
   327  	if volumeNodeComboState != AttachStateAttached {
   328  		t.Fatalf("%q/%q volume/node combo is marked %q; expected 'Attached'.", generatedVolumeName1, nodeName, volumeNodeComboState)
   329  	}
   330  
   331  	attachedVolumes := asw.GetAttachedVolumes()
   332  	if len(attachedVolumes) != 1 {
   333  		t.Fatalf("len(attachedVolumes) Expected: <1> Actual: <%v>", len(attachedVolumes))
   334  	}
   335  
   336  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName1, string(volumeName), nodeName, devicePath, true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
   337  }
   338  
   339  // Populates data struct with one volume/node entry.
   340  // Calls DeleteVolumeNode() to delete volume/node.
   341  // Verifies no volume/node entries exists.
   342  func Test_DeleteVolumeNode_Positive_VolumeExistsNodeExists(t *testing.T) {
   343  	// Arrange
   344  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
   345  	asw := NewActualStateOfWorld(volumePluginMgr)
   346  	volumeName := v1.UniqueVolumeName("volume-name")
   347  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   348  	nodeName := types.NodeName("node-name")
   349  	devicePath := "fake/device/path"
   350  	logger, _ := ktesting.NewTestContext(t)
   351  	generatedVolumeName, addErr := asw.AddVolumeNode(logger, volumeName, volumeSpec, nodeName, devicePath, true)
   352  	if addErr != nil {
   353  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", addErr)
   354  	}
   355  
   356  	// Act
   357  	asw.DeleteVolumeNode(generatedVolumeName, nodeName)
   358  
   359  	// Assert
   360  	volumeNodeComboState := asw.GetAttachState(generatedVolumeName, nodeName)
   361  	if volumeNodeComboState != AttachStateDetached {
   362  		t.Fatalf("%q/%q volume/node combo is marked %q, expected 'Detached'.", generatedVolumeName, nodeName, volumeNodeComboState)
   363  	}
   364  
   365  	attachedVolumes := asw.GetAttachedVolumes()
   366  	if len(attachedVolumes) != 0 {
   367  		t.Fatalf("len(attachedVolumes) Expected: <0> Actual: <%v>", len(attachedVolumes))
   368  	}
   369  }
   370  
   371  // Calls DeleteVolumeNode() to delete volume/node on empty data struct
   372  // Verifies no volume/node entries exists.
   373  func Test_DeleteVolumeNode_Positive_VolumeDoesntExistNodeDoesntExist(t *testing.T) {
   374  	// Arrange
   375  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
   376  	asw := NewActualStateOfWorld(volumePluginMgr)
   377  	volumeName := v1.UniqueVolumeName("volume-name")
   378  	nodeName := types.NodeName("node-name")
   379  
   380  	// Act
   381  	asw.DeleteVolumeNode(volumeName, nodeName)
   382  
   383  	// Assert
   384  	volumeNodeComboState := asw.GetAttachState(volumeName, nodeName)
   385  	if volumeNodeComboState != AttachStateDetached {
   386  		t.Fatalf("%q/%q volume/node combo is marked %q, expected 'Detached'.", volumeName, nodeName, volumeNodeComboState)
   387  	}
   388  
   389  	attachedVolumes := asw.GetAttachedVolumes()
   390  	if len(attachedVolumes) != 0 {
   391  		t.Fatalf("len(attachedVolumes) Expected: <0> Actual: <%v>", len(attachedVolumes))
   392  	}
   393  }
   394  
   395  // Populates data struct with two volume/node entries the second one using a
   396  // different node.
   397  // Calls DeleteVolumeNode() to delete first volume/node.
   398  // Verifies only second volume/node entry exists.
   399  func Test_DeleteVolumeNode_Positive_TwoNodesOneDeleted(t *testing.T) {
   400  	// Arrange
   401  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
   402  	asw := NewActualStateOfWorld(volumePluginMgr)
   403  	volumeName := v1.UniqueVolumeName("volume-name")
   404  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   405  	node1Name := types.NodeName("node1-name")
   406  	node2Name := types.NodeName("node2-name")
   407  	devicePath := "fake/device/path"
   408  	logger, _ := ktesting.NewTestContext(t)
   409  	generatedVolumeName1, add1Err := asw.AddVolumeNode(logger, volumeName, volumeSpec, node1Name, devicePath, true)
   410  	if add1Err != nil {
   411  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", add1Err)
   412  	}
   413  	generatedVolumeName2, add2Err := asw.AddVolumeNode(logger, volumeName, volumeSpec, node2Name, devicePath, true)
   414  	if add2Err != nil {
   415  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", add2Err)
   416  	}
   417  	if generatedVolumeName1 != generatedVolumeName2 {
   418  		t.Fatalf(
   419  			"Generated volume names for the same volume should be the same but they are not: %q and %q",
   420  			generatedVolumeName1,
   421  			generatedVolumeName2)
   422  	}
   423  
   424  	// Act
   425  	asw.DeleteVolumeNode(generatedVolumeName1, node1Name)
   426  
   427  	// Assert
   428  	volumeNodeComboState := asw.GetAttachState(generatedVolumeName1, node1Name)
   429  	if volumeNodeComboState != AttachStateDetached {
   430  		t.Fatalf("%q/%q volume/node combo is marked %q, expected 'Detached'.", generatedVolumeName1, node1Name, volumeNodeComboState)
   431  	}
   432  
   433  	volumeNodeComboState = asw.GetAttachState(generatedVolumeName1, node2Name)
   434  	if volumeNodeComboState != AttachStateAttached {
   435  		t.Fatalf("%q/%q volume/node combo is marked %q; expected 'Attached'.", generatedVolumeName1, node2Name, volumeNodeComboState)
   436  	}
   437  
   438  	attachedVolumes := asw.GetAttachedVolumes()
   439  	if len(attachedVolumes) != 1 {
   440  		t.Fatalf("len(attachedVolumes) Expected: <1> Actual: <%v>", len(attachedVolumes))
   441  	}
   442  
   443  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName1, string(volumeName), node2Name, devicePath, true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
   444  }
   445  
   446  // Populates data struct with one volume/node entry.
   447  // Calls GetAttachState() to verify entry.
   448  // Verifies the populated volume/node entry exists.
   449  func Test_VolumeNodeExists_Positive_VolumeExistsNodeExists(t *testing.T) {
   450  	// Arrange
   451  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
   452  	asw := NewActualStateOfWorld(volumePluginMgr)
   453  	volumeName := v1.UniqueVolumeName("volume-name")
   454  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   455  	nodeName := types.NodeName("node-name")
   456  	devicePath := "fake/device/path"
   457  	logger, _ := ktesting.NewTestContext(t)
   458  	generatedVolumeName, addErr := asw.AddVolumeNode(logger, volumeName, volumeSpec, nodeName, devicePath, true)
   459  	if addErr != nil {
   460  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", addErr)
   461  	}
   462  
   463  	// Act
   464  	volumeNodeComboState := asw.GetAttachState(generatedVolumeName, nodeName)
   465  
   466  	// Assert
   467  	if volumeNodeComboState != AttachStateAttached {
   468  		t.Fatalf("%q/%q volume/node combo is marked %q; expected 'Attached'.", generatedVolumeName, nodeName, volumeNodeComboState)
   469  	}
   470  
   471  	attachedVolumes := asw.GetAttachedVolumes()
   472  	if len(attachedVolumes) != 1 {
   473  		t.Fatalf("len(attachedVolumes) Expected: <1> Actual: <%v>", len(attachedVolumes))
   474  	}
   475  
   476  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName, string(volumeName), nodeName, devicePath, true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
   477  }
   478  
   479  // Populates data struct with one volume1/node1 entry.
   480  // Calls GetAttachState() with volume1/node2.
   481  // Verifies requested entry does not exist, but populated entry does.
   482  func Test_VolumeNodeExists_Positive_VolumeExistsNodeDoesntExist(t *testing.T) {
   483  	// Arrange
   484  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
   485  	asw := NewActualStateOfWorld(volumePluginMgr)
   486  	volumeName := v1.UniqueVolumeName("volume-name")
   487  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   488  	node1Name := types.NodeName("node1-name")
   489  	node2Name := types.NodeName("node2-name")
   490  	devicePath := "fake/device/path"
   491  	logger, _ := ktesting.NewTestContext(t)
   492  	generatedVolumeName, addErr := asw.AddVolumeNode(logger, volumeName, volumeSpec, node1Name, devicePath, true)
   493  	if addErr != nil {
   494  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", addErr)
   495  	}
   496  
   497  	// Act
   498  	volumeNodeComboState := asw.GetAttachState(generatedVolumeName, node2Name)
   499  
   500  	// Assert
   501  	if volumeNodeComboState != AttachStateDetached {
   502  		t.Fatalf("%q/%q volume/node combo is marked %q, expected 'Detached'.", generatedVolumeName, node2Name, volumeNodeComboState)
   503  	}
   504  
   505  	attachedVolumes := asw.GetAttachedVolumes()
   506  	if len(attachedVolumes) != 1 {
   507  		t.Fatalf("len(attachedVolumes) Expected: <1> Actual: <%v>", len(attachedVolumes))
   508  	}
   509  
   510  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName, string(volumeName), node1Name, devicePath, true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
   511  }
   512  
   513  // Calls GetAttachState() on empty data struct.
   514  // Verifies requested entry does not exist.
   515  func Test_VolumeNodeExists_Positive_VolumeAndNodeDontExist(t *testing.T) {
   516  	// Arrange
   517  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
   518  	asw := NewActualStateOfWorld(volumePluginMgr)
   519  	volumeName := v1.UniqueVolumeName("volume-name")
   520  	nodeName := types.NodeName("node-name")
   521  
   522  	// Act
   523  	volumeNodeComboState := asw.GetAttachState(volumeName, nodeName)
   524  
   525  	// Assert
   526  	if volumeNodeComboState != AttachStateDetached {
   527  		t.Fatalf("%q/%q volume/node combo is marked %q, expected 'Detached'.", volumeName, nodeName, volumeNodeComboState)
   528  	}
   529  
   530  	attachedVolumes := asw.GetAttachedVolumes()
   531  	if len(attachedVolumes) != 0 {
   532  		t.Fatalf("len(attachedVolumes) Expected: <0> Actual: <%v>", len(attachedVolumes))
   533  	}
   534  }
   535  
   536  // Calls GetAttachedVolumes() on empty data struct.
   537  // Verifies no volume/node entries are returned.
   538  func Test_GetAttachedVolumes_Positive_NoVolumesOrNodes(t *testing.T) {
   539  	// Arrange
   540  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
   541  	asw := NewActualStateOfWorld(volumePluginMgr)
   542  
   543  	// Act
   544  	attachedVolumes := asw.GetAttachedVolumes()
   545  
   546  	// Assert
   547  	if len(attachedVolumes) != 0 {
   548  		t.Fatalf("len(attachedVolumes) Expected: <0> Actual: <%v>", len(attachedVolumes))
   549  	}
   550  }
   551  
   552  // Populates data struct with one volume/node entry.
   553  // Calls GetAttachedVolumes() to get list of entries.
   554  // Verifies one volume/node entry is returned.
   555  func Test_GetAttachedVolumes_Positive_OneVolumeOneNode(t *testing.T) {
   556  	// Arrange
   557  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
   558  	asw := NewActualStateOfWorld(volumePluginMgr)
   559  	volumeName := v1.UniqueVolumeName("volume-name")
   560  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   561  	nodeName := types.NodeName("node-name")
   562  	devicePath := "fake/device/path"
   563  	logger, _ := ktesting.NewTestContext(t)
   564  	generatedVolumeName, addErr := asw.AddVolumeNode(logger, volumeName, volumeSpec, nodeName, devicePath, true)
   565  	if addErr != nil {
   566  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", addErr)
   567  	}
   568  
   569  	// Act
   570  	attachedVolumes := asw.GetAttachedVolumes()
   571  
   572  	// Assert
   573  	if len(attachedVolumes) != 1 {
   574  		t.Fatalf("len(attachedVolumes) Expected: <1> Actual: <%v>", len(attachedVolumes))
   575  	}
   576  
   577  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName, string(volumeName), nodeName, devicePath, true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
   578  }
   579  
   580  // Populates data struct with two volume/node entries (different node and volume).
   581  // Calls GetAttachedVolumes() to get list of entries.
   582  // Verifies both volume/node entries are returned.
   583  func Test_GetAttachedVolumes_Positive_TwoVolumeTwoNodes(t *testing.T) {
   584  	// Arrange
   585  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
   586  	asw := NewActualStateOfWorld(volumePluginMgr)
   587  	volume1Name := v1.UniqueVolumeName("volume1-name")
   588  	volume1Spec := controllervolumetesting.GetTestVolumeSpec(string(volume1Name), volume1Name)
   589  	node1Name := types.NodeName("node1-name")
   590  	devicePath := "fake/device/path"
   591  	logger, _ := ktesting.NewTestContext(t)
   592  	generatedVolumeName1, add1Err := asw.AddVolumeNode(logger, volume1Name, volume1Spec, node1Name, devicePath, true)
   593  	if add1Err != nil {
   594  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", add1Err)
   595  	}
   596  	volume2Name := v1.UniqueVolumeName("volume2-name")
   597  	volume2Spec := controllervolumetesting.GetTestVolumeSpec(string(volume2Name), volume2Name)
   598  	node2Name := types.NodeName("node2-name")
   599  	generatedVolumeName2, add2Err := asw.AddVolumeNode(logger, volume2Name, volume2Spec, node2Name, devicePath, true)
   600  	if add2Err != nil {
   601  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", add2Err)
   602  	}
   603  
   604  	// Act
   605  	attachedVolumes := asw.GetAttachedVolumes()
   606  
   607  	// Assert
   608  	if len(attachedVolumes) != 2 {
   609  		t.Fatalf("len(attachedVolumes) Expected: <2> Actual: <%v>", len(attachedVolumes))
   610  	}
   611  
   612  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName1, string(volume1Name), node1Name, devicePath, true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
   613  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName2, string(volume2Name), node2Name, devicePath, true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
   614  }
   615  
   616  // Populates data struct with two volume/node entries (same volume different node).
   617  // Calls GetAttachedVolumes() to get list of entries.
   618  // Verifies both volume/node entries are returned.
   619  func Test_GetAttachedVolumes_Positive_OneVolumeTwoNodes(t *testing.T) {
   620  	// Arrange
   621  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
   622  	asw := NewActualStateOfWorld(volumePluginMgr)
   623  	volumeName := v1.UniqueVolumeName("volume-name")
   624  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   625  	node1Name := types.NodeName("node1-name")
   626  	devicePath := "fake/device/path"
   627  	plugin, err := volumePluginMgr.FindAttachablePluginBySpec(volumeSpec)
   628  	if err != nil || plugin == nil {
   629  		t.Fatalf("Failed to get volume plugin from spec %v, %v", volumeSpec, err)
   630  	}
   631  	uniqueVolumeName, err := volumeutil.GetUniqueVolumeNameFromSpec(plugin, volumeSpec)
   632  	if err != nil || plugin == nil {
   633  		t.Fatalf("Failed to get uniqueVolumeName from spec %v, %v", volumeSpec, err)
   634  	}
   635  	logger, _ := ktesting.NewTestContext(t)
   636  	generatedVolumeName1, add1Err := asw.AddVolumeNode(logger, uniqueVolumeName, volumeSpec, node1Name, devicePath, true)
   637  	if add1Err != nil {
   638  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", add1Err)
   639  	}
   640  	node2Name := types.NodeName("node2-name")
   641  	generatedVolumeName2, add2Err := asw.AddVolumeNode(logger, v1.UniqueVolumeName(""), volumeSpec, node2Name, devicePath, true)
   642  	if add2Err != nil {
   643  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", add2Err)
   644  	}
   645  
   646  	if generatedVolumeName1 != generatedVolumeName2 {
   647  		t.Fatalf(
   648  			"Generated volume names for the same volume should be the same but they are not: %q and %q",
   649  			generatedVolumeName1,
   650  			generatedVolumeName2)
   651  	}
   652  
   653  	// Act
   654  	attachedVolumes := asw.GetAttachedVolumes()
   655  
   656  	// Assert
   657  	if len(attachedVolumes) != 2 {
   658  		t.Fatalf("len(attachedVolumes) Expected: <2> Actual: <%v>", len(attachedVolumes))
   659  	}
   660  
   661  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName1, string(volumeName), node1Name, devicePath, true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
   662  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName1, string(volumeName), node2Name, devicePath, true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
   663  }
   664  
   665  // Populates data struct with one volume/node entry.
   666  // Verifies mountedByNode is true and DetachRequestedTime is zero.
   667  func Test_SetVolumesMountedByNode_Positive_Set(t *testing.T) {
   668  	// Arrange
   669  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
   670  	asw := NewActualStateOfWorld(volumePluginMgr)
   671  	volumeName := v1.UniqueVolumeName("volume-name")
   672  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   673  	nodeName := types.NodeName("node-name")
   674  	devicePath := "fake/device/path"
   675  	logger, _ := ktesting.NewTestContext(t)
   676  	generatedVolumeName, addErr := asw.AddVolumeNode(logger, volumeName, volumeSpec, nodeName, devicePath, true)
   677  	if addErr != nil {
   678  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", addErr)
   679  	}
   680  
   681  	// Act: do not mark -- test default value
   682  
   683  	// Assert
   684  	attachedVolumes := asw.GetAttachedVolumes()
   685  	if len(attachedVolumes) != 1 {
   686  		t.Fatalf("len(attachedVolumes) Expected: <1> Actual: <%v>", len(attachedVolumes))
   687  	}
   688  
   689  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName, string(volumeName), nodeName, devicePath, true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
   690  }
   691  
   692  // Populates data struct with one volume/node entry.
   693  // Calls SetVolumesMountedByNode twice, first setting mounted to true then false.
   694  // Verifies mountedByNode is false.
   695  func Test_SetVolumesMountedByNode_Positive_UnsetWithInitialSet(t *testing.T) {
   696  	// Arrange
   697  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
   698  	asw := NewActualStateOfWorld(volumePluginMgr)
   699  	volumeName := v1.UniqueVolumeName("volume-name")
   700  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   701  	nodeName := types.NodeName("node-name")
   702  	devicePath := "fake/device/path"
   703  	logger, _ := ktesting.NewTestContext(t)
   704  	generatedVolumeName, addErr := asw.AddVolumeNode(logger, volumeName, volumeSpec, nodeName, devicePath, true)
   705  	if addErr != nil {
   706  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", addErr)
   707  	}
   708  
   709  	// Act
   710  	asw.SetVolumesMountedByNode(logger, []v1.UniqueVolumeName{generatedVolumeName}, nodeName)
   711  	asw.SetVolumesMountedByNode(logger, nil, nodeName)
   712  
   713  	attachedVolumes := asw.GetAttachedVolumes()
   714  	if len(attachedVolumes) != 1 {
   715  		t.Fatalf("len(attachedVolumes) Expected: <1> Actual: <%v>", len(attachedVolumes))
   716  	}
   717  
   718  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName, string(volumeName), nodeName, devicePath, false /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
   719  }
   720  
   721  // Populates data struct with one volume/node entry.
   722  // Calls SetVolumesMountedByNode once, setting mounted to false.
   723  // Verifies mountedByNode is false because value is overwritten
   724  func Test_SetVolumesMountedByNode_Positive_UnsetWithoutInitialSet(t *testing.T) {
   725  	// Arrange
   726  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
   727  	asw := NewActualStateOfWorld(volumePluginMgr)
   728  	volumeName := v1.UniqueVolumeName("volume-name")
   729  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   730  	nodeName := types.NodeName("node-name")
   731  	devicePath := "fake/device/path"
   732  	logger, _ := ktesting.NewTestContext(t)
   733  	generatedVolumeName, addErr := asw.AddVolumeNode(logger, volumeName, volumeSpec, nodeName, devicePath, true)
   734  	if addErr != nil {
   735  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", addErr)
   736  	}
   737  
   738  	attachedVolumes := asw.GetAttachedVolumes()
   739  	if len(attachedVolumes) != 1 {
   740  		t.Fatalf("len(attachedVolumes) Expected: <1> Actual: <%v>", len(attachedVolumes))
   741  	}
   742  
   743  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName, string(volumeName), nodeName, devicePath, true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
   744  
   745  	// Act
   746  	asw.SetVolumesMountedByNode(logger, nil, nodeName)
   747  
   748  	// Assert
   749  	attachedVolumes = asw.GetAttachedVolumes()
   750  	if len(attachedVolumes) != 1 {
   751  		t.Fatalf("len(attachedVolumes) Expected: <1> Actual: <%v>", len(attachedVolumes))
   752  	}
   753  
   754  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName, string(volumeName), nodeName, devicePath, false /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
   755  }
   756  
   757  // Populates data struct with one volume/node entry.
   758  // Calls SetVolumesMountedByNode twice, first setting mounted to true then false.
   759  // Calls AddVolumeNode to readd the same volume/node.
   760  // Verifies mountedByNode is false and detachRequestedTime is zero.
   761  func Test_SetVolumesMountedByNode_Positive_UnsetWithInitialSetAddVolumeNodeNotReset(t *testing.T) {
   762  	// Arrange
   763  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
   764  	asw := NewActualStateOfWorld(volumePluginMgr)
   765  	volumeName := v1.UniqueVolumeName("volume-name")
   766  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   767  	nodeName := types.NodeName("node-name")
   768  	devicePath := "fake/device/path"
   769  	logger, _ := ktesting.NewTestContext(t)
   770  	generatedVolumeName, addErr := asw.AddVolumeNode(logger, volumeName, volumeSpec, nodeName, devicePath, true)
   771  	if addErr != nil {
   772  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", addErr)
   773  	}
   774  
   775  	// Act
   776  	asw.SetVolumesMountedByNode(logger, []v1.UniqueVolumeName{generatedVolumeName}, nodeName)
   777  	asw.SetVolumesMountedByNode(logger, nil, nodeName)
   778  	generatedVolumeName, addErr = asw.AddVolumeNode(logger, volumeName, volumeSpec, nodeName, devicePath, true)
   779  
   780  	// Assert
   781  	if addErr != nil {
   782  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", addErr)
   783  	}
   784  
   785  	attachedVolumes := asw.GetAttachedVolumes()
   786  	if len(attachedVolumes) != 1 {
   787  		t.Fatalf("len(attachedVolumes) Expected: <1> Actual: <%v>", len(attachedVolumes))
   788  	}
   789  
   790  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName, string(volumeName), nodeName, devicePath, false /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
   791  }
   792  
   793  // Populates data struct with one volume/node entry.
   794  // Calls RemoveVolumeFromReportAsAttached() once on volume/node entry.
   795  // Calls SetVolumesMountedByNode() twice, first setting mounted to true then false.
   796  // Verifies mountedByNode is false and detachRequestedTime is NOT zero.
   797  func Test_SetVolumesMountedByNode_Positive_UnsetWithInitialSetVerifyDetachRequestedTimePerserved(t *testing.T) {
   798  	// Arrange
   799  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
   800  	asw := NewActualStateOfWorld(volumePluginMgr)
   801  	volumeName := v1.UniqueVolumeName("volume-name")
   802  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   803  	nodeName := types.NodeName("node-name")
   804  	devicePath := "fake/device/path"
   805  	logger, _ := ktesting.NewTestContext(t)
   806  	generatedVolumeName, addErr := asw.AddVolumeNode(logger, volumeName, volumeSpec, nodeName, devicePath, true)
   807  	if addErr != nil {
   808  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", addErr)
   809  	}
   810  	_, err := asw.SetDetachRequestTime(logger, generatedVolumeName, nodeName)
   811  	if err != nil {
   812  		t.Fatalf("SetDetachRequestTime failed. Expected: <no error> Actual: <%v>", err)
   813  	}
   814  	err = asw.RemoveVolumeFromReportAsAttached(generatedVolumeName, nodeName)
   815  	if err != nil {
   816  		t.Fatalf("RemoveVolumeFromReportAsAttached failed. Expected: <no error> Actual: <%v>", err)
   817  	}
   818  	expectedDetachRequestedTime := asw.GetAttachedVolumes()[0].DetachRequestedTime
   819  
   820  	// Act
   821  	asw.SetVolumesMountedByNode(logger, []v1.UniqueVolumeName{generatedVolumeName}, nodeName)
   822  	asw.SetVolumesMountedByNode(logger, nil, nodeName)
   823  
   824  	// Assert
   825  	attachedVolumes := asw.GetAttachedVolumes()
   826  	if len(attachedVolumes) != 1 {
   827  		t.Fatalf("len(attachedVolumes) Expected: <1> Actual: <%v>", len(attachedVolumes))
   828  	}
   829  
   830  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName, string(volumeName), nodeName, devicePath, false /* expectedMountedByNode */, true /* expectNonZeroDetachRequestedTime */)
   831  	if !expectedDetachRequestedTime.Equal(attachedVolumes[0].DetachRequestedTime) {
   832  		t.Fatalf("DetachRequestedTime changed. Expected: <%v> Actual: <%v>", expectedDetachRequestedTime, attachedVolumes[0].DetachRequestedTime)
   833  	}
   834  }
   835  
   836  // Populates data struct with one volume/node entry.
   837  // Verifies mountedByNode is true and detachRequestedTime is zero (default values).
   838  func Test_RemoveVolumeFromReportAsAttached_Positive_Set(t *testing.T) {
   839  	// Arrange
   840  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
   841  	asw := NewActualStateOfWorld(volumePluginMgr)
   842  	volumeName := v1.UniqueVolumeName("volume-name")
   843  	devicePath := "fake/device/path"
   844  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   845  	nodeName := types.NodeName("node-name")
   846  	logger, _ := ktesting.NewTestContext(t)
   847  	generatedVolumeName, addErr := asw.AddVolumeNode(logger, volumeName, volumeSpec, nodeName, devicePath, true)
   848  	if addErr != nil {
   849  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", addErr)
   850  	}
   851  
   852  	// Act: do not mark -- test default value
   853  
   854  	// Assert
   855  	attachedVolumes := asw.GetAttachedVolumes()
   856  	if len(attachedVolumes) != 1 {
   857  		t.Fatalf("len(attachedVolumes) Expected: <1> Actual: <%v>", len(attachedVolumes))
   858  	}
   859  
   860  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName, string(volumeName), nodeName, devicePath, true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
   861  }
   862  
   863  // Populates data struct with one volume/node entry.
   864  // Calls RemoveVolumeFromReportAsAttached() once on volume/node entry.
   865  // Verifies mountedByNode is true and detachRequestedTime is NOT zero.
   866  func Test_RemoveVolumeFromReportAsAttached_Positive_Marked(t *testing.T) {
   867  	// Arrange
   868  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
   869  	asw := NewActualStateOfWorld(volumePluginMgr)
   870  	volumeName := v1.UniqueVolumeName("volume-name")
   871  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   872  	nodeName := types.NodeName("node-name")
   873  	devicePath := "fake/device/path"
   874  	logger, _ := ktesting.NewTestContext(t)
   875  	generatedVolumeName, addErr := asw.AddVolumeNode(logger, volumeName, volumeSpec, nodeName, devicePath, true)
   876  	if addErr != nil {
   877  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", addErr)
   878  	}
   879  
   880  	// Act
   881  	_, err := asw.SetDetachRequestTime(logger, generatedVolumeName, nodeName)
   882  	if err != nil {
   883  		t.Fatalf("SetDetachRequestTime failed. Expected: <no error> Actual: <%v>", err)
   884  	}
   885  	markDesireToDetachErr := asw.RemoveVolumeFromReportAsAttached(generatedVolumeName, nodeName)
   886  	if markDesireToDetachErr != nil {
   887  		t.Fatalf("MarkDesireToDetach failed. Expected: <no error> Actual: <%v>", markDesireToDetachErr)
   888  	}
   889  
   890  	// Assert
   891  	attachedVolumes := asw.GetAttachedVolumes()
   892  	if len(attachedVolumes) != 1 {
   893  		t.Fatalf("len(attachedVolumes) Expected: <1> Actual: <%v>", len(attachedVolumes))
   894  	}
   895  
   896  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName, string(volumeName), nodeName, devicePath, true /* expectedMountedByNode */, true /* expectNonZeroDetachRequestedTime */)
   897  }
   898  
   899  // Populates data struct with one volume/node entry.
   900  // Calls MarkDesireToDetach() once on volume/node entry.
   901  // Calls ResetDetachRequestTime() to reset the detach request time value back to 0.
   902  // Verifies mountedByNode is true and detachRequestedTime is reset to zero.
   903  func Test_MarkDesireToDetach_Positive_MarkedAddVolumeNodeReset(t *testing.T) {
   904  	// Arrange
   905  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
   906  	asw := NewActualStateOfWorld(volumePluginMgr)
   907  	volumeName := v1.UniqueVolumeName("volume-name")
   908  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   909  	nodeName := types.NodeName("node-name")
   910  	devicePath := "fake/device/path"
   911  	logger, _ := ktesting.NewTestContext(t)
   912  	generatedVolumeName, addErr := asw.AddVolumeNode(logger, volumeName, volumeSpec, nodeName, devicePath, true)
   913  	if addErr != nil {
   914  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", addErr)
   915  	}
   916  
   917  	// Act
   918  	_, err := asw.SetDetachRequestTime(logger, generatedVolumeName, nodeName)
   919  	if err != nil {
   920  		t.Fatalf("SetDetachRequestTime failed. Expected: <no error> Actual: <%v>", err)
   921  	}
   922  	markDesireToDetachErr := asw.RemoveVolumeFromReportAsAttached(generatedVolumeName, nodeName)
   923  	// Reset detach request time to 0
   924  	asw.ResetDetachRequestTime(logger, generatedVolumeName, nodeName)
   925  
   926  	// Assert
   927  	if markDesireToDetachErr != nil {
   928  		t.Fatalf("RemoveVolumeFromReportAsAttached failed. Expected: <no error> Actual: <%v>", markDesireToDetachErr)
   929  	}
   930  	if addErr != nil {
   931  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", addErr)
   932  	}
   933  
   934  	// Assert
   935  	attachedVolumes := asw.GetAttachedVolumes()
   936  	if len(attachedVolumes) != 1 {
   937  		t.Fatalf("len(attachedVolumes) Expected: <1> Actual: <%v>", len(attachedVolumes))
   938  	}
   939  
   940  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName, string(volumeName), nodeName, devicePath, true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
   941  }
   942  
   943  // Populates data struct with one volume/node entry.
   944  // Calls SetVolumesMountedByNode() twice, first setting mounted to true then false.
   945  // Calls RemoveVolumeFromReportAsAttached() once on volume/node entry.
   946  // Verifies mountedByNode is false and detachRequestedTime is NOT zero.
   947  func Test_RemoveVolumeFromReportAsAttached_Positive_UnsetWithInitialSetVolumesMountedByNodePreserved(t *testing.T) {
   948  	// Arrange
   949  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
   950  	asw := NewActualStateOfWorld(volumePluginMgr)
   951  	volumeName := v1.UniqueVolumeName("volume-name")
   952  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   953  	nodeName := types.NodeName("node-name")
   954  	devicePath := "fake/device/path"
   955  	logger, _ := ktesting.NewTestContext(t)
   956  	generatedVolumeName, addErr := asw.AddVolumeNode(logger, volumeName, volumeSpec, nodeName, devicePath, true)
   957  	if addErr != nil {
   958  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", addErr)
   959  	}
   960  	asw.SetVolumesMountedByNode(logger, []v1.UniqueVolumeName{generatedVolumeName}, nodeName)
   961  	asw.SetVolumesMountedByNode(logger, nil, nodeName)
   962  	// Act
   963  	_, err := asw.SetDetachRequestTime(logger, generatedVolumeName, nodeName)
   964  	if err != nil {
   965  		t.Fatalf("SetDetachRequestTime failed. Expected: <no error> Actual: <%v>", err)
   966  	}
   967  	removeVolumeDetachErr := asw.RemoveVolumeFromReportAsAttached(generatedVolumeName, nodeName)
   968  	if removeVolumeDetachErr != nil {
   969  		t.Fatalf("RemoveVolumeFromReportAsAttached failed. Expected: <no error> Actual: <%v>", removeVolumeDetachErr)
   970  	}
   971  
   972  	// Assert
   973  	attachedVolumes := asw.GetAttachedVolumes()
   974  	if len(attachedVolumes) != 1 {
   975  		t.Fatalf("len(attachedVolumes) Expected: <1> Actual: <%v>", len(attachedVolumes))
   976  	}
   977  
   978  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName, string(volumeName), nodeName, devicePath, false /* expectedMountedByNode */, true /* expectNonZeroDetachRequestedTime */)
   979  }
   980  
   981  // Populates data struct with one volume/node entry.
   982  // Calls RemoveVolumeFromReportAsAttached
   983  // Verifies there is no volume as reported as attached
   984  func Test_RemoveVolumeFromReportAsAttached(t *testing.T) {
   985  	// Arrange
   986  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
   987  	asw := NewActualStateOfWorld(volumePluginMgr)
   988  	volumeName := v1.UniqueVolumeName("volume-name")
   989  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   990  	nodeName := types.NodeName("node-name")
   991  	devicePath := "fake/device/path"
   992  	logger, _ := ktesting.NewTestContext(t)
   993  	generatedVolumeName, addErr := asw.AddVolumeNode(logger, volumeName, volumeSpec, nodeName, devicePath, true)
   994  	if addErr != nil {
   995  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", addErr)
   996  	}
   997  
   998  	removeVolumeDetachErr := asw.RemoveVolumeFromReportAsAttached(generatedVolumeName, nodeName)
   999  	if removeVolumeDetachErr != nil {
  1000  		t.Fatalf("RemoveVolumeFromReportAsAttached failed. Expected: <no error> Actual: <%v>", removeVolumeDetachErr)
  1001  	}
  1002  
  1003  	reportAsAttachedVolumesMap := asw.GetVolumesToReportAttached(logger)
  1004  	volumes, exists := reportAsAttachedVolumesMap[nodeName]
  1005  	if !exists {
  1006  		t.Fatalf("MarkDesireToDetach_UnmarkDesireToDetach failed. Expected: <node %q exist> Actual: <node does not exist in the reportedAsAttached map", nodeName)
  1007  	}
  1008  	if len(volumes) > 0 {
  1009  		t.Fatalf("len(reportAsAttachedVolumes) Expected: <0> Actual: <%v>", len(volumes))
  1010  	}
  1011  
  1012  }
  1013  
  1014  // Populates data struct with one volume/node entry.
  1015  // Calls RemoveVolumeFromReportAsAttached
  1016  // Calls AddVolumeToReportAsAttached to add volume back as attached
  1017  // Verifies there is one volume as reported as attached
  1018  func Test_RemoveVolumeFromReportAsAttached_AddVolumeToReportAsAttached_Positive(t *testing.T) {
  1019  	// Arrange
  1020  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
  1021  	asw := NewActualStateOfWorld(volumePluginMgr)
  1022  	volumeName := v1.UniqueVolumeName("volume-name")
  1023  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
  1024  	nodeName := types.NodeName("node-name")
  1025  	devicePath := "fake/device/path"
  1026  	logger, _ := ktesting.NewTestContext(t)
  1027  	generatedVolumeName, addErr := asw.AddVolumeNode(logger, volumeName, volumeSpec, nodeName, devicePath, true)
  1028  	if addErr != nil {
  1029  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", addErr)
  1030  	}
  1031  
  1032  	removeVolumeDetachErr := asw.RemoveVolumeFromReportAsAttached(generatedVolumeName, nodeName)
  1033  	if removeVolumeDetachErr != nil {
  1034  		t.Fatalf("RemoveVolumeFromReportAsAttached failed. Expected: <no error> Actual: <%v>", removeVolumeDetachErr)
  1035  	}
  1036  
  1037  	reportAsAttachedVolumesMap := asw.GetVolumesToReportAttached(logger)
  1038  	volumes, exists := reportAsAttachedVolumesMap[nodeName]
  1039  	if !exists {
  1040  		t.Fatalf("Test_RemoveVolumeFromReportAsAttached_AddVolumeToReportAsAttached_Positive failed. Expected: <node %q exist> Actual: <node does not exist in the reportedAsAttached map", nodeName)
  1041  	}
  1042  	if len(volumes) > 0 {
  1043  		t.Fatalf("len(reportAsAttachedVolumes) Expected: <0> Actual: <%v>", len(volumes))
  1044  	}
  1045  
  1046  	asw.AddVolumeToReportAsAttached(logger, generatedVolumeName, nodeName)
  1047  	reportAsAttachedVolumesMap = asw.GetVolumesToReportAttached(logger)
  1048  	volumes, exists = reportAsAttachedVolumesMap[nodeName]
  1049  	if !exists {
  1050  		t.Fatalf("Test_RemoveVolumeFromReportAsAttached_AddVolumeToReportAsAttached_Positive failed. Expected: <node %q exist> Actual: <node does not exist in the reportedAsAttached map", nodeName)
  1051  	}
  1052  	if len(volumes) != 1 {
  1053  		t.Fatalf("len(reportAsAttachedVolumes) Expected: <1> Actual: <%v>", len(volumes))
  1054  	}
  1055  }
  1056  
  1057  // Populates data struct with one volume/node entry.
  1058  // Calls RemoveVolumeFromReportAsAttached
  1059  // Calls DeleteVolumeNode
  1060  // Calls AddVolumeNode
  1061  // Verifies there is no volume as reported as attached
  1062  func Test_RemoveVolumeFromReportAsAttached_Delete_AddVolumeNode(t *testing.T) {
  1063  	// Arrange
  1064  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
  1065  	asw := NewActualStateOfWorld(volumePluginMgr)
  1066  	volumeName := v1.UniqueVolumeName("volume-name")
  1067  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
  1068  	nodeName := types.NodeName("node-name")
  1069  	devicePath := "fake/device/path"
  1070  	logger, _ := ktesting.NewTestContext(t)
  1071  	generatedVolumeName, addErr := asw.AddVolumeNode(logger, volumeName, volumeSpec, nodeName, devicePath, true)
  1072  	if addErr != nil {
  1073  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", addErr)
  1074  	}
  1075  
  1076  	removeVolumeDetachErr := asw.RemoveVolumeFromReportAsAttached(generatedVolumeName, nodeName)
  1077  	if removeVolumeDetachErr != nil {
  1078  		t.Fatalf("RemoveVolumeFromReportAsAttached failed. Expected: <no error> Actual: <%v>", removeVolumeDetachErr)
  1079  	}
  1080  
  1081  	reportAsAttachedVolumesMap := asw.GetVolumesToReportAttached(logger)
  1082  	volumes, exists := reportAsAttachedVolumesMap[nodeName]
  1083  	if !exists {
  1084  		t.Fatalf("Test_RemoveVolumeFromReportAsAttached_Delete_AddVolumeNode failed. Expected: <node %q exists> Actual: <node does not exist in the reportedAsAttached map", nodeName)
  1085  	}
  1086  	if len(volumes) > 0 {
  1087  		t.Fatalf("len(reportAsAttachedVolumes) Expected: <0> Actual: <%v>", len(volumes))
  1088  	}
  1089  
  1090  	asw.DeleteVolumeNode(generatedVolumeName, nodeName)
  1091  
  1092  	asw.AddVolumeNode(logger, volumeName, volumeSpec, nodeName, "" /*device path*/, true)
  1093  
  1094  	reportAsAttachedVolumesMap = asw.GetVolumesToReportAttached(logger)
  1095  	volumes, exists = reportAsAttachedVolumesMap[nodeName]
  1096  	if !exists {
  1097  		t.Fatalf("Test_RemoveVolumeFromReportAsAttached_Delete_AddVolumeNode failed. Expected: <node %q exists> Actual: <node does not exist in the reportedAsAttached map", nodeName)
  1098  	}
  1099  	if len(volumes) != 1 {
  1100  		t.Fatalf("len(reportAsAttachedVolumes) Expected: <1> Actual: <%v>", len(volumes))
  1101  	}
  1102  }
  1103  
  1104  // Populates data struct with one volume/node entry.
  1105  // Calls SetDetachRequestTime twice and sleep maxWaitTime (1 second) in between
  1106  // The elapsed time returned from the first SetDetachRequestTime call should be smaller than maxWaitTime
  1107  // The elapsed time returned from the second SetDetachRequestTime call should be larger than maxWaitTime
  1108  func Test_SetDetachRequestTime_Positive(t *testing.T) {
  1109  	// Arrange
  1110  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
  1111  	asw := NewActualStateOfWorld(volumePluginMgr)
  1112  	volumeName := v1.UniqueVolumeName("volume-name")
  1113  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
  1114  	nodeName := types.NodeName("node-name")
  1115  	devicePath := "fake/device/path"
  1116  	logger, _ := ktesting.NewTestContext(t)
  1117  	generatedVolumeName, addErr := asw.AddVolumeNode(logger, volumeName, volumeSpec, nodeName, devicePath, true)
  1118  	if addErr != nil {
  1119  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", addErr)
  1120  	}
  1121  
  1122  	maxWaitTime := 1 * time.Second
  1123  	etime, err := asw.SetDetachRequestTime(logger, generatedVolumeName, nodeName)
  1124  	if err != nil {
  1125  		t.Fatalf("SetDetachRequestTime failed. Expected: <no error> Actual: <%v>", err)
  1126  	}
  1127  	if etime >= maxWaitTime {
  1128  		t.Logf("SetDetachRequestTim Expected: <elapsed time %v is smaller than maxWaitTime %v> Actual <elapsed time is larger than maxWaitTime>", etime, maxWaitTime)
  1129  	}
  1130  	// Sleep and call SetDetachRequestTime again
  1131  	time.Sleep(maxWaitTime)
  1132  	etime, err = asw.SetDetachRequestTime(logger, generatedVolumeName, nodeName)
  1133  	if err != nil {
  1134  		t.Fatalf("SetDetachRequestTime failed. Expected: <no error> Actual: <%v>", err)
  1135  	}
  1136  	if etime < maxWaitTime {
  1137  		t.Fatalf("SetDetachRequestTim Expected: <elapsed time %v is larger than maxWaitTime %v> Actual <elapsed time is smaller>", etime, maxWaitTime)
  1138  	}
  1139  }
  1140  
  1141  func Test_GetAttachedVolumesForNode_Positive_NoVolumesOrNodes(t *testing.T) {
  1142  	// Arrange
  1143  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
  1144  	asw := NewActualStateOfWorld(volumePluginMgr)
  1145  	node := types.NodeName("random")
  1146  
  1147  	// Act
  1148  	attachedVolumes := asw.GetAttachedVolumesForNode(node)
  1149  
  1150  	// Assert
  1151  	if len(attachedVolumes) != 0 {
  1152  		t.Fatalf("len(attachedVolumes) Expected: <0> Actual: <%v>", len(attachedVolumes))
  1153  	}
  1154  }
  1155  
  1156  func Test_GetAttachedVolumesForNode_Positive_OneVolumeOneNode(t *testing.T) {
  1157  	// Arrange
  1158  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
  1159  	asw := NewActualStateOfWorld(volumePluginMgr)
  1160  	volumeName := v1.UniqueVolumeName("volume-name")
  1161  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
  1162  	nodeName := types.NodeName("node-name")
  1163  	devicePath := "fake/device/path"
  1164  	logger, _ := ktesting.NewTestContext(t)
  1165  	generatedVolumeName, addErr := asw.AddVolumeNode(logger, volumeName, volumeSpec, nodeName, devicePath, true)
  1166  	if addErr != nil {
  1167  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", addErr)
  1168  	}
  1169  
  1170  	// Act
  1171  	attachedVolumes := asw.GetAttachedVolumesForNode(nodeName)
  1172  
  1173  	// Assert
  1174  	if len(attachedVolumes) != 1 {
  1175  		t.Fatalf("len(attachedVolumes) Expected: <1> Actual: <%v>", len(attachedVolumes))
  1176  	}
  1177  
  1178  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName, string(volumeName), nodeName, devicePath, true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
  1179  }
  1180  
  1181  func Test_GetAttachedVolumesForNode_Positive_TwoVolumeTwoNodes(t *testing.T) {
  1182  	// Arrange
  1183  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
  1184  	asw := NewActualStateOfWorld(volumePluginMgr)
  1185  	volume1Name := v1.UniqueVolumeName("volume1-name")
  1186  	volume1Spec := controllervolumetesting.GetTestVolumeSpec(string(volume1Name), volume1Name)
  1187  	node1Name := types.NodeName("node1-name")
  1188  	devicePath := "fake/device/path"
  1189  	logger, _ := ktesting.NewTestContext(t)
  1190  	_, add1Err := asw.AddVolumeNode(logger, volume1Name, volume1Spec, node1Name, devicePath, true)
  1191  	if add1Err != nil {
  1192  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", add1Err)
  1193  	}
  1194  	volume2Name := v1.UniqueVolumeName("volume2-name")
  1195  	volume2Spec := controllervolumetesting.GetTestVolumeSpec(string(volume2Name), volume2Name)
  1196  	node2Name := types.NodeName("node2-name")
  1197  	generatedVolumeName2, add2Err := asw.AddVolumeNode(logger, volume2Name, volume2Spec, node2Name, devicePath, true)
  1198  	if add2Err != nil {
  1199  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", add2Err)
  1200  	}
  1201  
  1202  	// Act
  1203  	attachedVolumes := asw.GetAttachedVolumesForNode(node2Name)
  1204  
  1205  	// Assert
  1206  	if len(attachedVolumes) != 1 {
  1207  		t.Fatalf("len(attachedVolumes) Expected: <1> Actual: <%v>", len(attachedVolumes))
  1208  	}
  1209  
  1210  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName2, string(volume2Name), node2Name, devicePath, true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
  1211  }
  1212  
  1213  func Test_GetAttachedVolumesForNode_Positive_OneVolumeTwoNodes(t *testing.T) {
  1214  	// Arrange
  1215  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
  1216  	asw := NewActualStateOfWorld(volumePluginMgr)
  1217  	volumeName := v1.UniqueVolumeName("volume-name")
  1218  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
  1219  	node1Name := types.NodeName("node1-name")
  1220  	devicePath := "fake/device/path"
  1221  	logger, _ := ktesting.NewTestContext(t)
  1222  	plugin, err := volumePluginMgr.FindAttachablePluginBySpec(volumeSpec)
  1223  	if err != nil || plugin == nil {
  1224  		t.Fatalf("Failed to get volume plugin from spec %v, %v", volumeSpec, err)
  1225  	}
  1226  	uniqueVolumeName, err := volumeutil.GetUniqueVolumeNameFromSpec(plugin, volumeSpec)
  1227  	if err != nil || plugin == nil {
  1228  		t.Fatalf("Failed to get uniqueVolumeName from spec %v, %v", volumeSpec, err)
  1229  	}
  1230  	generatedVolumeName1, add1Err := asw.AddVolumeNode(logger, uniqueVolumeName, volumeSpec, node1Name, devicePath, true)
  1231  	if add1Err != nil {
  1232  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", add1Err)
  1233  	}
  1234  	node2Name := types.NodeName("node2-name")
  1235  	generatedVolumeName2, add2Err := asw.AddVolumeNode(logger, v1.UniqueVolumeName(""), volumeSpec, node2Name, devicePath, true)
  1236  	if add2Err != nil {
  1237  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", add2Err)
  1238  	}
  1239  
  1240  	if generatedVolumeName1 != generatedVolumeName2 {
  1241  		t.Fatalf(
  1242  			"Generated volume names for the same volume should be the same but they are not: %q and %q",
  1243  			generatedVolumeName1,
  1244  			generatedVolumeName2)
  1245  	}
  1246  
  1247  	// Act
  1248  	attachedVolumes := asw.GetAttachedVolumesForNode(node1Name)
  1249  
  1250  	// Assert
  1251  	if len(attachedVolumes) != 1 {
  1252  		t.Fatalf("len(attachedVolumes) Expected: <1> Actual: <%v>", len(attachedVolumes))
  1253  	}
  1254  
  1255  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName1, string(volumeName), node1Name, devicePath, true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
  1256  }
  1257  
  1258  func Test_OneVolumeTwoNodes_TwoDevicePaths(t *testing.T) {
  1259  	// Arrange
  1260  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
  1261  	asw := NewActualStateOfWorld(volumePluginMgr)
  1262  	volumeName := v1.UniqueVolumeName("volume-name")
  1263  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
  1264  	node1Name := types.NodeName("node1-name")
  1265  	devicePath1 := "fake/device/path1"
  1266  	logger, _ := ktesting.NewTestContext(t)
  1267  	plugin, err := volumePluginMgr.FindAttachablePluginBySpec(volumeSpec)
  1268  	if err != nil || plugin == nil {
  1269  		t.Fatalf("Failed to get volume plugin from spec %v, %v", volumeSpec, err)
  1270  	}
  1271  	uniqueVolumeName, err := volumeutil.GetUniqueVolumeNameFromSpec(plugin, volumeSpec)
  1272  	if err != nil || plugin == nil {
  1273  		t.Fatalf("Failed to get uniqueVolumeName from spec %v, %v", volumeSpec, err)
  1274  	}
  1275  	generatedVolumeName1, add1Err := asw.AddVolumeNode(logger, uniqueVolumeName, volumeSpec, node1Name, devicePath1, true)
  1276  	if add1Err != nil {
  1277  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", add1Err)
  1278  	}
  1279  	node2Name := types.NodeName("node2-name")
  1280  	devicePath2 := "fake/device/path2"
  1281  	generatedVolumeName2, add2Err := asw.AddVolumeNode(logger, v1.UniqueVolumeName(""), volumeSpec, node2Name, devicePath2, true)
  1282  	if add2Err != nil {
  1283  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", add2Err)
  1284  	}
  1285  
  1286  	if generatedVolumeName1 != generatedVolumeName2 {
  1287  		t.Fatalf(
  1288  			"Generated volume names for the same volume should be the same but they are not: %q and %q",
  1289  			generatedVolumeName1,
  1290  			generatedVolumeName2)
  1291  	}
  1292  
  1293  	// Act
  1294  	attachedVolumes := asw.GetAttachedVolumesForNode(node2Name)
  1295  
  1296  	// Assert
  1297  	if len(attachedVolumes) != 1 {
  1298  		t.Fatalf("len(attachedVolumes) Expected: <1> Actual: <%v>", len(attachedVolumes))
  1299  	}
  1300  
  1301  	verifyAttachedVolume(t, attachedVolumes, generatedVolumeName2, string(volumeName), node2Name, devicePath2, true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
  1302  }
  1303  
  1304  // Test_SetNodeStatusUpdateNeededError expects the map nodesToUpdateStatusFor
  1305  // to be empty if the SetNodeStatusUpdateNeeded is called on a node that
  1306  // does not exist in the actual state of the world
  1307  func Test_SetNodeStatusUpdateNeededError(t *testing.T) {
  1308  	// Arrange
  1309  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
  1310  	asw := NewActualStateOfWorld(volumePluginMgr)
  1311  	nodeName := types.NodeName("node-1")
  1312  
  1313  	// Act
  1314  	logger, _ := ktesting.NewTestContext(t)
  1315  	asw.SetNodeStatusUpdateNeeded(logger, nodeName)
  1316  
  1317  	// Assert
  1318  	nodesToUpdateStatusFor := asw.GetNodesToUpdateStatusFor()
  1319  	if len(nodesToUpdateStatusFor) != 0 {
  1320  		t.Fatalf("nodesToUpdateStatusFor should be empty as nodeName does not exist")
  1321  	}
  1322  }
  1323  
  1324  // Test_updateNodeStatusUpdateNeeded expects statusUpdateNeeded to be properly updated if
  1325  // updateNodeStatusUpdateNeeded is called on a node that exists in the actual state of the world
  1326  func Test_updateNodeStatusUpdateNeeded(t *testing.T) {
  1327  	// Arrange
  1328  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
  1329  	asw := &actualStateOfWorld{
  1330  		attachedVolumes:        make(map[v1.UniqueVolumeName]attachedVolume),
  1331  		nodesToUpdateStatusFor: make(map[types.NodeName]nodeToUpdateStatusFor),
  1332  		volumePluginMgr:        volumePluginMgr,
  1333  	}
  1334  	nodeName := types.NodeName("node-1")
  1335  	nodeToUpdate := nodeToUpdateStatusFor{
  1336  		nodeName:                  nodeName,
  1337  		statusUpdateNeeded:        true,
  1338  		volumesToReportAsAttached: make(map[v1.UniqueVolumeName]v1.UniqueVolumeName),
  1339  	}
  1340  	asw.nodesToUpdateStatusFor[nodeName] = nodeToUpdate
  1341  
  1342  	// Act
  1343  	err := asw.updateNodeStatusUpdateNeeded(nodeName, false)
  1344  
  1345  	// Assert
  1346  	if err != nil {
  1347  		t.Fatalf("updateNodeStatusUpdateNeeded should not return error, but got: %v", err)
  1348  	}
  1349  	nodesToUpdateStatusFor := asw.GetNodesToUpdateStatusFor()
  1350  	if nodesToUpdateStatusFor[nodeName].statusUpdateNeeded {
  1351  		t.Fatalf("nodesToUpdateStatusFor should be updated to: false, but got: true")
  1352  	}
  1353  }
  1354  
  1355  // Test_updateNodeStatusUpdateNeededError expects statusUpdateNeeded to report error if
  1356  // updateNodeStatusUpdateNeeded is called on a node that does not exist in the actual state of the world
  1357  func Test_updateNodeStatusUpdateNeededError(t *testing.T) {
  1358  	// Arrange
  1359  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
  1360  	asw := &actualStateOfWorld{
  1361  		attachedVolumes:        make(map[v1.UniqueVolumeName]attachedVolume),
  1362  		nodesToUpdateStatusFor: make(map[types.NodeName]nodeToUpdateStatusFor),
  1363  		volumePluginMgr:        volumePluginMgr,
  1364  	}
  1365  	nodeName := types.NodeName("node-1")
  1366  
  1367  	// Act
  1368  	err := asw.updateNodeStatusUpdateNeeded(nodeName, false)
  1369  
  1370  	// Assert
  1371  	if err == nil {
  1372  		t.Fatalf("updateNodeStatusUpdateNeeded should return error, but got nothing")
  1373  	}
  1374  }
  1375  
  1376  // Mark a volume as attached to a node.
  1377  // Verify GetAttachState returns AttachedState
  1378  // Verify GetAttachedVolumes return this volume
  1379  func Test_MarkVolumeAsAttached(t *testing.T) {
  1380  	// Arrange
  1381  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
  1382  	asw := NewActualStateOfWorld(volumePluginMgr)
  1383  	volumeName := v1.UniqueVolumeName("volume-name")
  1384  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
  1385  
  1386  	nodeName := types.NodeName("node-name")
  1387  	devicePath := "fake/device/path"
  1388  
  1389  	plugin, err := volumePluginMgr.FindAttachablePluginBySpec(volumeSpec)
  1390  	if err != nil || plugin == nil {
  1391  		t.Fatalf("Failed to get volume plugin from spec %v, %v", volumeSpec, err)
  1392  	}
  1393  
  1394  	// Act
  1395  	logger, _ := ktesting.NewTestContext(t)
  1396  	err = asw.MarkVolumeAsAttached(logger, volumeName, volumeSpec, nodeName, devicePath)
  1397  
  1398  	// Assert
  1399  	if err != nil {
  1400  		t.Fatalf("MarkVolumeAsAttached failed. Expected: <no error> Actual: <%v>", err)
  1401  	}
  1402  
  1403  	volumeNodeComboState := asw.GetAttachState(volumeName, nodeName)
  1404  	if volumeNodeComboState != AttachStateAttached {
  1405  		t.Fatalf("asw says the volume: %q is not attached (%v) to node:%q, it should.",
  1406  			volumeName, AttachStateAttached, nodeName)
  1407  	}
  1408  	attachedVolumes := asw.GetAttachedVolumes()
  1409  	if len(attachedVolumes) != 1 {
  1410  		t.Fatalf("len(attachedVolumes) Expected: <1> Actual: <%v>", len(attachedVolumes))
  1411  	}
  1412  	verifyAttachedVolume(t, attachedVolumes, volumeName, string(volumeName), nodeName, devicePath, true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
  1413  }
  1414  
  1415  // Mark a volume as attachment as uncertain.
  1416  // Verify GetAttachState returns UncertainState
  1417  // Verify GetAttachedVolumes return this volume
  1418  func Test_MarkVolumeAsUncertain(t *testing.T) {
  1419  	// Arrange
  1420  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
  1421  	asw := NewActualStateOfWorld(volumePluginMgr)
  1422  	volumeName := v1.UniqueVolumeName("volume-name")
  1423  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
  1424  	nodeName := types.NodeName("node-name")
  1425  
  1426  	plugin, err := volumePluginMgr.FindAttachablePluginBySpec(volumeSpec)
  1427  	if err != nil || plugin == nil {
  1428  		t.Fatalf("Failed to get volume plugin from spec %v, %v", volumeSpec, err)
  1429  	}
  1430  
  1431  	// Act
  1432  	logger, _ := ktesting.NewTestContext(t)
  1433  	err = asw.MarkVolumeAsUncertain(logger, volumeName, volumeSpec, nodeName)
  1434  
  1435  	// Assert
  1436  	if err != nil {
  1437  		t.Fatalf("MarkVolumeAsUncertain failed. Expected: <no error> Actual: <%v>", err)
  1438  	}
  1439  	volumeNodeComboState := asw.GetAttachState(volumeName, nodeName)
  1440  	if volumeNodeComboState != AttachStateUncertain {
  1441  		t.Fatalf("asw says the volume: %q is attached (%v) to node:%q, it should not.",
  1442  			volumeName, volumeNodeComboState, nodeName)
  1443  	}
  1444  	attachedVolumes := asw.GetAttachedVolumes()
  1445  	if len(attachedVolumes) != 1 {
  1446  		t.Fatalf("len(attachedVolumes) Expected: <1> Actual: <%v>", len(attachedVolumes))
  1447  	}
  1448  	verifyAttachedVolume(t, attachedVolumes, volumeName, string(volumeName), nodeName, "", true /* expectedMountedByNode */, false /* expectNonZeroDetachRequestedTime */)
  1449  }
  1450  
  1451  // Calls AddVolumeNode() once with attached set to true.
  1452  // Verifies GetVolumesToReportAttachedForNode has an update for the node.
  1453  // Call GetVolumesToReportAttachedForNode a second time for the node, verify it does not report
  1454  // an update is needed any more
  1455  // Then calls RemoveVolumeFromReportAsAttached()
  1456  // Verifies GetVolumesToReportAttachedForNode reports an update is needed
  1457  func Test_GetVolumesToReportAttachedForNode_Positive(t *testing.T) {
  1458  	// Arrange
  1459  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
  1460  	asw := NewActualStateOfWorld(volumePluginMgr)
  1461  	volumeName := v1.UniqueVolumeName("volume-name")
  1462  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
  1463  
  1464  	nodeName := types.NodeName("node-name")
  1465  	devicePath := "fake/device/path"
  1466  
  1467  	// Act
  1468  	logger, _ := ktesting.NewTestContext(t)
  1469  	generatedVolumeName, err := asw.AddVolumeNode(logger, volumeName, volumeSpec, nodeName, devicePath, true)
  1470  
  1471  	// Assert
  1472  	if err != nil {
  1473  		t.Fatalf("AddVolumeNode failed. Expected: <no error> Actual: <%v>", err)
  1474  	}
  1475  
  1476  	needsUpdate, attachedVolumes := asw.GetVolumesToReportAttachedForNode(logger, nodeName)
  1477  	if !needsUpdate {
  1478  		t.Fatalf("GetVolumesToReportAttachedForNode_Positive_NewVolumeNewNodeWithTrueAttached failed. Actual: <node %q does not need an update> Expect: <node exists in the reportedAsAttached map and needs an update", nodeName)
  1479  	}
  1480  	if len(attachedVolumes) != 1 {
  1481  		t.Fatalf("len(attachedVolumes) Expected: <1> Actual: <%v>", len(attachedVolumes))
  1482  	}
  1483  
  1484  	needsUpdate, _ = asw.GetVolumesToReportAttachedForNode(logger, nodeName)
  1485  	if needsUpdate {
  1486  		t.Fatalf("GetVolumesToReportAttachedForNode_Positive_NewVolumeNewNodeWithTrueAttached failed. Actual: <node %q needs an update> Expect: <node exists in the reportedAsAttached map and does not need an update", nodeName)
  1487  	}
  1488  
  1489  	removeVolumeDetachErr := asw.RemoveVolumeFromReportAsAttached(generatedVolumeName, nodeName)
  1490  	if removeVolumeDetachErr != nil {
  1491  		t.Fatalf("RemoveVolumeFromReportAsAttached failed. Expected: <no error> Actual: <%v>", removeVolumeDetachErr)
  1492  	}
  1493  
  1494  	needsUpdate, attachedVolumes = asw.GetVolumesToReportAttachedForNode(logger, nodeName)
  1495  	if !needsUpdate {
  1496  		t.Fatalf("GetVolumesToReportAttachedForNode_Positive_NewVolumeNewNodeWithTrueAttached failed. Actual: <node %q does not need an update> Expect: <node exists in the reportedAsAttached map and needs an update", nodeName)
  1497  	}
  1498  	if len(attachedVolumes) != 0 {
  1499  		t.Fatalf("len(attachedVolumes) Expected: <0> Actual: <%v>", len(attachedVolumes))
  1500  	}
  1501  }
  1502  
  1503  // Verifies GetVolumesToReportAttachedForNode reports no update needed for an unknown node.
  1504  func Test_GetVolumesToReportAttachedForNode_UnknownNode(t *testing.T) {
  1505  	// Arrange
  1506  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
  1507  	asw := NewActualStateOfWorld(volumePluginMgr)
  1508  	nodeName := types.NodeName("node-name")
  1509  	logger, _ := ktesting.NewTestContext(t)
  1510  	needsUpdate, _ := asw.GetVolumesToReportAttachedForNode(logger, nodeName)
  1511  	if needsUpdate {
  1512  		t.Fatalf("GetVolumesToReportAttachedForNode_UnknownNode failed. Actual: <node %q needs an update> Expect: <node does not exist in the reportedAsAttached map and does not need an update", nodeName)
  1513  	}
  1514  }
  1515  
  1516  func verifyAttachedVolume(
  1517  	t *testing.T,
  1518  	attachedVolumes []AttachedVolume,
  1519  	expectedVolumeName v1.UniqueVolumeName,
  1520  	expectedVolumeSpecName string,
  1521  	expectedNodeName types.NodeName,
  1522  	expectedDevicePath string,
  1523  	expectedMountedByNode,
  1524  	expectNonZeroDetachRequestedTime bool) {
  1525  	for _, attachedVolume := range attachedVolumes {
  1526  		if attachedVolume.VolumeName == expectedVolumeName &&
  1527  			attachedVolume.VolumeSpec.Name() == expectedVolumeSpecName &&
  1528  			attachedVolume.NodeName == expectedNodeName &&
  1529  			attachedVolume.DevicePath == expectedDevicePath &&
  1530  			attachedVolume.MountedByNode == expectedMountedByNode &&
  1531  			attachedVolume.DetachRequestedTime.IsZero() == !expectNonZeroDetachRequestedTime {
  1532  			return
  1533  		}
  1534  	}
  1535  
  1536  	t.Fatalf(
  1537  		"attachedVolumes (%v) should contain the volume/node combo %q/%q with DevicePath=%q MountedByNode=%v and NonZeroDetachRequestedTime=%v. It does not.",
  1538  		attachedVolumes,
  1539  		expectedVolumeName,
  1540  		expectedNodeName,
  1541  		expectedDevicePath,
  1542  		expectedMountedByNode,
  1543  		expectNonZeroDetachRequestedTime)
  1544  }