github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/systests/profile_test.go (about)

     1  package systests
     2  
     3  import (
     4  	"context"
     5  
     6  	"io"
     7  	"net/http"
     8  	"testing"
     9  
    10  	"github.com/davecgh/go-spew/spew"
    11  	"github.com/keybase/client/go/engine"
    12  	"github.com/keybase/client/go/kbtest"
    13  	"github.com/keybase/client/go/libkb"
    14  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    15  	"github.com/stretchr/testify/require"
    16  )
    17  
    18  func TestProofSuggestions(t *testing.T) {
    19  	tt := newTeamTester(t)
    20  	defer tt.cleanup()
    21  
    22  	alice := tt.addUser("abc")
    23  
    24  	res, err := alice.userClient.ProofSuggestions(context.Background(), 0)
    25  	require.NoError(t, err)
    26  	t.Logf("suggestions: %v", spew.Sdump(res))
    27  	expected := keybase1.ProofSuggestionsRes{
    28  		ShowMore: true,
    29  		Suggestions: []keybase1.ProofSuggestion{{
    30  			Key:           "twitter",
    31  			ProfileText:   "Prove your Twitter",
    32  			PickerText:    "Twitter",
    33  			PickerSubtext: "twitter.com",
    34  		}, {
    35  			Key:           "github",
    36  			ProfileText:   "Prove your GitHub",
    37  			PickerText:    "GitHub",
    38  			PickerSubtext: "github.com",
    39  		}, {
    40  			Key:           "reddit",
    41  			ProfileText:   "Prove your Reddit",
    42  			PickerText:    "Reddit",
    43  			PickerSubtext: "reddit.com",
    44  		}, {
    45  			Key:           "hackernews",
    46  			ProfileText:   "Prove your Hacker News",
    47  			PickerText:    "Hacker News",
    48  			PickerSubtext: "news.ycombinator.com",
    49  		}, {
    50  			Key:           "rooter",
    51  			ProfileText:   "Prove your Rooter",
    52  			PickerText:    "Rooter",
    53  			PickerSubtext: "",
    54  		}, {
    55  			Key:           "gubble.social",
    56  			ProfileText:   "Prove your Gubble.social",
    57  			PickerText:    "Gubble.social",
    58  			PickerSubtext: "Gubble instance",
    59  		}, {
    60  			Key:           "web",
    61  			ProfileText:   "Prove your website",
    62  			PickerText:    "Your own website",
    63  			PickerSubtext: "",
    64  		}, {
    65  			Key:           "pgp",
    66  			ProfileText:   "Add a PGP key",
    67  			PickerText:    "PGP key",
    68  			PickerSubtext: "",
    69  		}, {
    70  			Key:           "btc",
    71  			ProfileText:   "Set a Bitcoin address",
    72  			PickerText:    "Bitcoin address",
    73  			PickerSubtext: "",
    74  		}, {
    75  			Key:           "zcash",
    76  			ProfileText:   "Set a Zcash address",
    77  			PickerText:    "Zcash address",
    78  			PickerSubtext: "",
    79  		}, {
    80  			Key:           "gubble.cloud",
    81  			BelowFold:     true,
    82  			ProfileText:   "Prove your Gubble.cloud",
    83  			PickerText:    "Gubble.cloud",
    84  			PickerSubtext: "Gubble instance",
    85  		}, {
    86  			Key:           "theqrl.org",
    87  			BelowFold:     true,
    88  			ProfileText:   "Prove your Quantum Resistant Ledger",
    89  			PickerText:    "Quantum Resistant Ledger",
    90  			PickerSubtext: "theqrl.org",
    91  		}}}
    92  	require.Equal(t, expected.ShowMore, res.ShowMore)
    93  	require.True(t, len(res.Suggestions) >= len(expected.Suggestions), "should be at least as many results as expected")
    94  	iconExempt := map[string]struct{}{
    95  		"gubble-with-dashes.dot": {},
    96  		"mastodon.local":         {},
    97  	}
    98  	for _, b := range res.Suggestions {
    99  		if _, exempt := iconExempt[b.Key]; exempt {
   100  			// Skip checking for logos for this one.
   101  			continue
   102  		}
   103  		require.Len(t, b.ProfileIcon, 2)
   104  		for _, icon := range b.ProfileIcon {
   105  			checkIcon(t, icon)
   106  		}
   107  		require.Len(t, b.ProfileIconDarkmode, 2)
   108  		for _, icon := range b.ProfileIconDarkmode {
   109  			checkIcon(t, icon)
   110  		}
   111  		require.Len(t, b.ProfileIcon, 2)
   112  		for _, icon := range b.PickerIcon {
   113  			checkIcon(t, icon)
   114  		}
   115  		require.Len(t, b.PickerIconDarkmode, 2)
   116  		for _, icon := range b.PickerIconDarkmode {
   117  			checkIcon(t, icon)
   118  		}
   119  
   120  	}
   121  	var found int
   122  	for i, b := range res.Suggestions {
   123  		if found >= len(expected.Suggestions) {
   124  			t.Logf("done")
   125  			break
   126  		}
   127  		t.Logf("row %v %v", i, b.Key)
   128  		a := expected.Suggestions[found]
   129  		if a.Key != b.Key {
   130  			t.Logf("skipping %v (mismatch)", a.Key)
   131  			continue
   132  		}
   133  		found++
   134  		require.Equal(t, a.Key, b.Key)
   135  		require.Equal(t, a.BelowFold, b.BelowFold)
   136  		require.Equal(t, a.ProfileText, b.ProfileText)
   137  		require.Equal(t, a.PickerText, b.PickerText)
   138  		require.Equal(t, a.PickerSubtext, b.PickerSubtext)
   139  
   140  	}
   141  	require.Len(t, expected.Suggestions, found)
   142  }
   143  
   144  func checkIcon(t testing.TB, icon keybase1.SizedImage) {
   145  	if icon.Width < 2 {
   146  		t.Fatalf("unreasonable icon size")
   147  	}
   148  	if kbtest.SkipIconRemoteTest() {
   149  		t.Logf("Skipping icon remote test")
   150  		require.True(t, len(icon.Path) > 8)
   151  	} else {
   152  		resp, err := http.Get(icon.Path)
   153  		require.Equal(t, 200, resp.StatusCode, "icon file should be reachable: %v", icon.Path)
   154  		require.NoError(t, err)
   155  		body, err := io.ReadAll(resp.Body)
   156  		require.NoError(t, err)
   157  		if len(body) < 150 {
   158  			t.Fatalf("unreasonable icon payload size")
   159  		}
   160  	}
   161  }
   162  
   163  func TestProofSuggestionsOmitProven(t *testing.T) {
   164  	tt := newTeamTester(t)
   165  	defer tt.cleanup()
   166  	alice := tt.addUser("abc")
   167  
   168  	assertOmitted := func(service string) {
   169  		res, err := alice.userClient.ProofSuggestions(context.Background(), 0)
   170  		require.NoError(t, err)
   171  		for _, suggestion := range res.Suggestions {
   172  			require.NotEqual(t, service, suggestion.Key)
   173  		}
   174  	}
   175  
   176  	alice.proveRooter()
   177  	t.Logf("alice proved rooter, so rooter is no longer suggested")
   178  	assertOmitted("rooter")
   179  
   180  	eng := engine.NewCryptocurrencyEngine(alice.MetaContext().G(), keybase1.RegisterAddressArg{
   181  		Address: "zcCk6rKzynC4tT1Rmg325A5Xw81Ck3S6nD6mtPWCXaMtyFczkyU4kYjEhrcz2QKfF5T2siWGyJNxWo43XWT3qk5YpPhFGj2",
   182  	})
   183  	err := engine.RunEngine2(alice.MetaContext().WithUIs(libkb.UIs{
   184  		LogUI:    alice.MetaContext().G().Log,
   185  		SecretUI: alice.newSecretUI(),
   186  	}), eng)
   187  	require.NoError(t, err)
   188  	t.Logf("alice added a zcash address, so zcash is no longer suggested")
   189  	assertOmitted("zcash")
   190  }