github.com/sl1pm4t/consul@v1.4.5-0.20190325224627-74c31c540f9c/command/acl/token/clone/token_clone_test.go (about) 1 package tokenclone 2 3 import ( 4 "os" 5 "regexp" 6 "strconv" 7 "strings" 8 "testing" 9 10 "github.com/hashicorp/consul/agent" 11 "github.com/hashicorp/consul/api" 12 "github.com/hashicorp/consul/logger" 13 "github.com/hashicorp/consul/testrpc" 14 "github.com/hashicorp/consul/testutil" 15 "github.com/mitchellh/cli" 16 "github.com/stretchr/testify/require" 17 ) 18 19 func parseCloneOutput(t *testing.T, output string) *api.ACLToken { 20 // This will only work for non-legacy tokens 21 re := regexp.MustCompile("Token cloned successfully.\n" + 22 "AccessorID: ([a-zA-Z0-9\\-]{36})\n" + 23 "SecretID: ([a-zA-Z0-9\\-]{36})\n" + 24 "Description: ([^\n]*)\n" + 25 "Local: (true|false)\n" + 26 "Create Time: ([^\n]+)\n" + 27 "Policies:\n" + 28 "( [a-zA-Z0-9\\-]{36} - [^\n]+\n)*") 29 30 submatches := re.FindStringSubmatch(output) 31 require.Lenf(t, submatches, 7, "Didn't match: %q", output) 32 33 local, err := strconv.ParseBool(submatches[4]) 34 require.NoError(t, err) 35 36 token := &api.ACLToken{ 37 AccessorID: submatches[1], 38 SecretID: submatches[2], 39 Description: submatches[3], 40 Local: local, 41 } 42 43 if len(submatches[6]) > 0 { 44 policyRe := regexp.MustCompile(" ([a-zA-Z0-9\\-]{36}) - ([^\n]+)") 45 for _, m := range policyRe.FindAllStringSubmatch(submatches[6], -1) { 46 token.Policies = append(token.Policies, &api.ACLTokenPolicyLink{ID: m[1], Name: m[2]}) 47 } 48 } 49 50 return token 51 } 52 53 func TestTokenCloneCommand_noTabs(t *testing.T) { 54 t.Parallel() 55 56 if strings.ContainsRune(New(cli.NewMockUi()).Help(), '\t') { 57 t.Fatal("help has tabs") 58 } 59 } 60 61 func TestTokenCloneCommand(t *testing.T) { 62 t.Parallel() 63 req := require.New(t) 64 65 testDir := testutil.TempDir(t, "acl") 66 defer os.RemoveAll(testDir) 67 68 a := agent.NewTestAgent(t, t.Name(), ` 69 primary_datacenter = "dc1" 70 acl { 71 enabled = true 72 tokens { 73 master = "root" 74 } 75 }`) 76 77 a.Agent.LogWriter = logger.NewLogWriter(512) 78 79 defer a.Shutdown() 80 testrpc.WaitForLeader(t, a.RPC, "dc1") 81 82 // Create a policy 83 client := a.Client() 84 85 _, _, err := client.ACL().PolicyCreate( 86 &api.ACLPolicy{Name: "test-policy"}, 87 &api.WriteOptions{Token: "root"}, 88 ) 89 req.NoError(err) 90 91 // create a token 92 token, _, err := client.ACL().TokenCreate( 93 &api.ACLToken{Description: "test", Policies: []*api.ACLTokenPolicyLink{&api.ACLTokenPolicyLink{Name: "test-policy"}}}, 94 &api.WriteOptions{Token: "root"}, 95 ) 96 req.NoError(err) 97 98 // clone with description 99 t.Run("Description", func(t *testing.T) { 100 ui := cli.NewMockUi() 101 cmd := New(ui) 102 103 args := []string{ 104 "-http-addr=" + a.HTTPAddr(), 105 "-id=" + token.AccessorID, 106 "-token=root", 107 "-description=test cloned", 108 } 109 110 code := cmd.Run(args) 111 req.Empty(ui.ErrorWriter.String()) 112 req.Equal(code, 0) 113 114 cloned := parseCloneOutput(t, ui.OutputWriter.String()) 115 116 req.Equal("test cloned", cloned.Description) 117 req.Len(cloned.Policies, 1) 118 119 apiToken, _, err := client.ACL().TokenRead( 120 cloned.AccessorID, 121 &api.QueryOptions{Token: "root"}, 122 ) 123 124 req.NoError(err) 125 req.NotNil(apiToken) 126 127 req.Equal(cloned.AccessorID, apiToken.AccessorID) 128 req.Equal(cloned.SecretID, apiToken.SecretID) 129 req.Equal(cloned.Description, apiToken.Description) 130 req.Equal(cloned.Local, apiToken.Local) 131 req.Equal(cloned.Policies, apiToken.Policies) 132 }) 133 134 // clone without description 135 t.Run("Without Description", func(t *testing.T) { 136 ui := cli.NewMockUi() 137 cmd := New(ui) 138 139 args := []string{ 140 "-http-addr=" + a.HTTPAddr(), 141 "-id=" + token.AccessorID, 142 "-token=root", 143 } 144 145 code := cmd.Run(args) 146 req.Equal(code, 0) 147 req.Empty(ui.ErrorWriter.String()) 148 149 cloned := parseCloneOutput(t, ui.OutputWriter.String()) 150 151 req.Equal("test", cloned.Description) 152 req.Len(cloned.Policies, 1) 153 154 apiToken, _, err := client.ACL().TokenRead( 155 cloned.AccessorID, 156 &api.QueryOptions{Token: "root"}, 157 ) 158 159 req.NoError(err) 160 req.NotNil(apiToken) 161 162 req.Equal(cloned.AccessorID, apiToken.AccessorID) 163 req.Equal(cloned.SecretID, apiToken.SecretID) 164 req.Equal(cloned.Description, apiToken.Description) 165 req.Equal(cloned.Local, apiToken.Local) 166 req.Equal(cloned.Policies, apiToken.Policies) 167 }) 168 }