@@ -33,10 +33,13 @@ import (
33
33
apiequality "k8s.io/apimachinery/pkg/api/equality"
34
34
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
35
35
"k8s.io/apimachinery/pkg/runtime"
36
+ "k8s.io/apimachinery/pkg/runtime/schema"
36
37
"k8s.io/apimachinery/pkg/util/intstr"
37
38
"k8s.io/cli-runtime/pkg/genericclioptions"
38
39
restclient "k8s.io/client-go/rest"
39
40
"k8s.io/client-go/rest/fake"
41
+ "k8s.io/client-go/tools/remotecommand"
42
+ "k8s.io/kubectl/pkg/cmd/attach"
40
43
"k8s.io/kubectl/pkg/cmd/delete"
41
44
cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
42
45
cmdutil "k8s.io/kubectl/pkg/cmd/util"
@@ -640,6 +643,193 @@ func TestExpose(t *testing.T) {
640
643
}
641
644
}
642
645
646
+ func TestRunAttach (t * testing.T ) {
647
+ tests := []struct {
648
+ name string
649
+ rm bool
650
+ quiet bool
651
+ deleteErrorMessage string
652
+ expectedDeleteCount int
653
+ expectedOut string
654
+ expectedErrOut string
655
+ }{
656
+ {
657
+ name : "test attach" ,
658
+ rm : false ,
659
+ quiet : false ,
660
+ expectedDeleteCount : 0 ,
661
+ expectedOut : "" ,
662
+ expectedErrOut : "If you don't see a command prompt, try pressing enter.\n " ,
663
+ },
664
+ {
665
+ name : "test attach with quiet" ,
666
+ rm : false ,
667
+ quiet : true ,
668
+ expectedDeleteCount : 0 ,
669
+ expectedOut : "" ,
670
+ expectedErrOut : "" ,
671
+ },
672
+ {
673
+ name : "test attach with rm" ,
674
+ rm : true ,
675
+ quiet : false ,
676
+ expectedDeleteCount : 1 ,
677
+ expectedOut : "pod \" foo\" deleted\n " ,
678
+ expectedErrOut : "If you don't see a command prompt, try pressing enter.\n " ,
679
+ },
680
+ {
681
+ name : "test attach with rm should not print message if quiet is specified" ,
682
+ rm : true ,
683
+ quiet : true ,
684
+ expectedDeleteCount : 1 ,
685
+ expectedOut : "" ,
686
+ expectedErrOut : "" ,
687
+ },
688
+ {
689
+ name : "error should be displayed if delete fails" ,
690
+ rm : true ,
691
+ quiet : false ,
692
+ deleteErrorMessage : "delete error message" ,
693
+ expectedDeleteCount : 1 ,
694
+ expectedOut : "" ,
695
+ expectedErrOut : "If you don't see a command prompt, try pressing enter.\n Delete failed: delete error message\n " ,
696
+ },
697
+ }
698
+
699
+ fakePod := & corev1.Pod {
700
+ TypeMeta : metav1.TypeMeta {
701
+ APIVersion : "v1" ,
702
+ Kind : "Pod" ,
703
+ },
704
+ ObjectMeta : metav1.ObjectMeta {
705
+ Name : "foo" ,
706
+ Namespace : "default" ,
707
+ },
708
+ Spec : corev1.PodSpec {
709
+ Containers : []corev1.Container {
710
+ {
711
+ Name : "bar" ,
712
+ },
713
+ },
714
+ },
715
+ Status : corev1.PodStatus {
716
+ Phase : corev1 .PodRunning ,
717
+ Conditions : []corev1.PodCondition {
718
+ {
719
+ Type : corev1 .PodReady ,
720
+ Status : corev1 .ConditionTrue ,
721
+ },
722
+ },
723
+ },
724
+ }
725
+
726
+ for _ , test := range tests {
727
+ t .Run (test .name , func (tt * testing.T ) {
728
+ postCount := 0
729
+ attachCount := 0
730
+ deleteCount := 0
731
+
732
+ attachFunc = func (o * attach.AttachOptions , containerToAttach * corev1.Container , raw bool , sizeQueue remotecommand.TerminalSizeQueue ) func () error {
733
+ if containerToAttach .Name != "bar" {
734
+ tt .Fatalf ("expected attach to container name \" bar\" , but got %q" , containerToAttach .Name )
735
+ }
736
+ return func () error {
737
+ attachCount ++
738
+ return nil
739
+ }
740
+ }
741
+
742
+ tf := cmdtesting .NewTestFactory ().WithNamespace ("test" )
743
+ defer tf .Cleanup ()
744
+
745
+ codec := scheme .Codecs .LegacyCodec (scheme .Scheme .PrioritizedVersionsAllGroups ()... )
746
+ ns := scheme .Codecs .WithoutConversion ()
747
+ tf .Client = & fake.RESTClient {
748
+ GroupVersion : schema.GroupVersion {Version : "" },
749
+ NegotiatedSerializer : ns ,
750
+ Client : fake .CreateHTTPClient (func (req * http.Request ) (* http.Response , error ) {
751
+ switch p , m := req .URL .Path , req .Method ; {
752
+ case m == "POST" && p == "/namespaces/test/pods" :
753
+ postCount ++
754
+ body := cmdtesting .ObjBody (codec , fakePod )
755
+ return & http.Response {StatusCode : http .StatusOK , Header : cmdtesting .DefaultHeader (), Body : body }, nil
756
+ case m == "GET" && p == "/api/v1/namespaces/default/pods" :
757
+ event := & metav1.WatchEvent {
758
+ Type : "ADDED" ,
759
+ Object : runtime.RawExtension {Object : fakePod },
760
+ }
761
+ body := cmdtesting .ObjBody (codec , event )
762
+ return & http.Response {StatusCode : http .StatusOK , Header : cmdtesting .DefaultHeader (), Body : body }, nil
763
+ case m == "GET" && p == "/namespaces/default/pods/foo" :
764
+ body := cmdtesting .ObjBody (codec , fakePod )
765
+ return & http.Response {StatusCode : http .StatusOK , Header : cmdtesting .DefaultHeader (), Body : body }, nil
766
+ case m == "DELETE" && p == "/namespaces/default/pods/foo" :
767
+ deleteCount ++
768
+ if test .deleteErrorMessage != "" {
769
+ body := cmdtesting .ObjBody (codec , & metav1.Status {
770
+ Status : metav1 .StatusFailure ,
771
+ Message : test .deleteErrorMessage ,
772
+ })
773
+ return & http.Response {StatusCode : http .StatusInternalServerError , Header : cmdtesting .DefaultHeader (), Body : body }, nil
774
+ } else {
775
+ body := cmdtesting .ObjBody (codec , fakePod )
776
+ return & http.Response {StatusCode : http .StatusOK , Header : cmdtesting .DefaultHeader (), Body : body }, nil
777
+ }
778
+ default :
779
+ tt .Errorf ("unexpected request: %s %#v\n %#v" , req .Method , req .URL , req )
780
+ return nil , fmt .Errorf ("unexpected request" )
781
+ }
782
+ }),
783
+ }
784
+
785
+ tf .ClientConfigVal = & restclient.Config {
786
+ ContentConfig : restclient.ContentConfig {GroupVersion : & schema.GroupVersion {Version : "" }, NegotiatedSerializer : ns },
787
+ }
788
+
789
+ streams , _ , bufOut , bufErr := genericclioptions .NewTestIOStreams ()
790
+ cmdutil .BehaviorOnFatal (func (str string , code int ) {
791
+ bufErr .Write ([]byte (str ))
792
+ })
793
+
794
+ cmd := NewCmdRun (tf , streams )
795
+ cmd .Flags ().Set ("image" , "test-image" )
796
+ cmd .Flags ().Set ("attach" , "true" )
797
+ if test .rm {
798
+ cmd .Flags ().Set ("rm" , "true" )
799
+ }
800
+ if test .quiet {
801
+ cmd .Flags ().Set ("quiet" , "true" )
802
+ }
803
+
804
+ parentCmd := cobra.Command {}
805
+ parentCmd .AddCommand (cmd )
806
+
807
+ cmd .Run (cmd , []string {"test-pod" })
808
+
809
+ if postCount != 1 {
810
+ tt .Fatalf ("expected 1 post request, but got %d" , postCount )
811
+ }
812
+
813
+ if attachCount != 1 {
814
+ tt .Fatalf ("expected 1 attach call, but got %d" , attachCount )
815
+ }
816
+
817
+ if deleteCount != test .expectedDeleteCount {
818
+ tt .Fatalf ("expected %d delete requests, but got %d" , test .expectedDeleteCount , deleteCount )
819
+ }
820
+
821
+ if bufErr .String () != test .expectedErrOut {
822
+ tt .Fatalf ("unexpected error. got: %q, expected: %q" , bufErr .String (), test .expectedErrOut )
823
+ }
824
+
825
+ if bufOut .String () != test .expectedOut {
826
+ tt .Fatalf ("unexpected output. got: %q, expected: %q" , bufOut .String (), test .expectedOut )
827
+ }
828
+ })
829
+
830
+ }
831
+ }
832
+
643
833
func TestRunOverride (t * testing.T ) {
644
834
tests := []struct {
645
835
name string
0 commit comments