github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/daemon/api_buy_unsupp_test.go (about)

     1  /*
     2   * Copyright (C) 2014-2020 Canonical Ltd
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License version 3 as
     6   * published by the Free Software Foundation.
     7   *
     8   * This program is distributed in the hope that it will be useful,
     9   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    10   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11   * GNU General Public License for more details.
    12   *
    13   * You should have received a copy of the GNU General Public License
    14   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15   *
    16   */
    17  
    18  package daemon_test
    19  
    20  import (
    21  	"bytes"
    22  	"fmt"
    23  	"net/http"
    24  
    25  	"gopkg.in/check.v1"
    26  
    27  	"github.com/snapcore/snapd/client"
    28  	"github.com/snapcore/snapd/daemon"
    29  	"github.com/snapcore/snapd/overlord/auth"
    30  	"github.com/snapcore/snapd/store"
    31  )
    32  
    33  var _ = check.Suite(&buySuite{})
    34  
    35  type buySuite struct {
    36  	apiBaseSuite
    37  
    38  	user *auth.UserState
    39  	err  error
    40  
    41  	buyOptions *client.BuyOptions
    42  	buyResult  *client.BuyResult
    43  }
    44  
    45  func (s *buySuite) Buy(options *client.BuyOptions, user *auth.UserState) (*client.BuyResult, error) {
    46  	s.pokeStateLock()
    47  
    48  	s.buyOptions = options
    49  	s.user = user
    50  	return s.buyResult, s.err
    51  }
    52  
    53  func (s *buySuite) ReadyToBuy(user *auth.UserState) error {
    54  	s.pokeStateLock()
    55  
    56  	s.user = user
    57  	return s.err
    58  }
    59  
    60  func (s *buySuite) SetUpTest(c *check.C) {
    61  	s.apiBaseSuite.SetUpTest(c)
    62  
    63  	s.user = nil
    64  	s.err = nil
    65  	s.buyOptions = nil
    66  	s.buyResult = nil
    67  
    68  	s.daemonWithStore(c, s)
    69  
    70  	s.expectAuthenticatedAccess()
    71  }
    72  
    73  const validBuyInput = `{
    74  		  "snap-id": "the-snap-id-1234abcd",
    75  		  "snap-name": "the snap name",
    76  		  "price": 1.23,
    77  		  "currency": "EUR"
    78  		}`
    79  
    80  var validBuyOptions = &client.BuyOptions{
    81  	SnapID:   "the-snap-id-1234abcd",
    82  	Price:    1.23,
    83  	Currency: "EUR",
    84  }
    85  
    86  var buyTests = []struct {
    87  	input                string
    88  	result               *client.BuyResult
    89  	err                  error
    90  	expectedStatus       int
    91  	expectedResult       interface{}
    92  	expectedResponseType daemon.ResponseType
    93  	expectedBuyOptions   *client.BuyOptions
    94  }{
    95  	{
    96  		// Success
    97  		input: validBuyInput,
    98  		result: &client.BuyResult{
    99  			State: "Complete",
   100  		},
   101  		expectedStatus: 200,
   102  		expectedResult: &client.BuyResult{
   103  			State: "Complete",
   104  		},
   105  		expectedResponseType: daemon.ResponseTypeSync,
   106  		expectedBuyOptions:   validBuyOptions,
   107  	},
   108  	{
   109  		// Fail with internal error
   110  		input: `{
   111  		  "snap-id": "the-snap-id-1234abcd",
   112  		  "price": 1.23,
   113  		  "currency": "EUR"
   114  		}`,
   115  		err:                  fmt.Errorf("internal error banana"),
   116  		expectedStatus:       500,
   117  		expectedResponseType: daemon.ResponseTypeError,
   118  		expectedResult: &daemon.ErrorResult{
   119  			Message: "internal error banana",
   120  		},
   121  		expectedBuyOptions: &client.BuyOptions{
   122  			SnapID:   "the-snap-id-1234abcd",
   123  			Price:    1.23,
   124  			Currency: "EUR",
   125  		},
   126  	},
   127  	{
   128  		// Fail with unauthenticated error
   129  		input:                validBuyInput,
   130  		err:                  store.ErrUnauthenticated,
   131  		expectedStatus:       400,
   132  		expectedResponseType: daemon.ResponseTypeError,
   133  		expectedResult: &daemon.ErrorResult{
   134  			Message: "you need to log in first",
   135  			Kind:    "login-required",
   136  		},
   137  		expectedBuyOptions: validBuyOptions,
   138  	},
   139  	{
   140  		// Fail with TOS not accepted
   141  		input:                validBuyInput,
   142  		err:                  store.ErrTOSNotAccepted,
   143  		expectedStatus:       400,
   144  		expectedResponseType: daemon.ResponseTypeError,
   145  		expectedResult: &daemon.ErrorResult{
   146  			Message: "terms of service not accepted",
   147  			Kind:    "terms-not-accepted",
   148  		},
   149  		expectedBuyOptions: validBuyOptions,
   150  	},
   151  	{
   152  		// Fail with no payment methods
   153  		input:                validBuyInput,
   154  		err:                  store.ErrNoPaymentMethods,
   155  		expectedStatus:       400,
   156  		expectedResponseType: daemon.ResponseTypeError,
   157  		expectedResult: &daemon.ErrorResult{
   158  			Message: "no payment methods",
   159  			Kind:    "no-payment-methods",
   160  		},
   161  		expectedBuyOptions: validBuyOptions,
   162  	},
   163  	{
   164  		// Fail with payment declined
   165  		input:                validBuyInput,
   166  		err:                  store.ErrPaymentDeclined,
   167  		expectedStatus:       400,
   168  		expectedResponseType: daemon.ResponseTypeError,
   169  		expectedResult: &daemon.ErrorResult{
   170  			Message: "payment declined",
   171  			Kind:    "payment-declined",
   172  		},
   173  		expectedBuyOptions: validBuyOptions,
   174  	},
   175  }
   176  
   177  func (s *buySuite) TestBuySnap(c *check.C) {
   178  	user := &auth.UserState{
   179  		Username: "username",
   180  		Email:    "email@test.com",
   181  	}
   182  
   183  	for _, test := range buyTests {
   184  		s.buyResult = test.result
   185  		s.err = test.err
   186  
   187  		buf := bytes.NewBufferString(test.input)
   188  		req, err := http.NewRequest("POST", "/v2/buy", buf)
   189  		c.Assert(err, check.IsNil)
   190  
   191  		rsp := s.jsonReq(c, req, user)
   192  
   193  		c.Check(rsp.Status, check.Equals, test.expectedStatus)
   194  		c.Check(rsp.Type, check.Equals, test.expectedResponseType)
   195  		c.Assert(rsp.Result, check.FitsTypeOf, test.expectedResult)
   196  		c.Check(rsp.Result, check.DeepEquals, test.expectedResult)
   197  
   198  		c.Check(s.buyOptions, check.DeepEquals, test.expectedBuyOptions)
   199  		c.Check(s.user, check.Equals, user)
   200  	}
   201  }
   202  
   203  var readyToBuyTests = []struct {
   204  	input    error
   205  	status   int
   206  	respType interface{}
   207  	response interface{}
   208  }{
   209  	{
   210  		// Success
   211  		input:    nil,
   212  		status:   200,
   213  		respType: daemon.ResponseTypeSync,
   214  		response: true,
   215  	},
   216  	{
   217  		// Not accepted TOS
   218  		input:    store.ErrTOSNotAccepted,
   219  		status:   400,
   220  		respType: daemon.ResponseTypeError,
   221  		response: &daemon.ErrorResult{
   222  			Message: "terms of service not accepted",
   223  			Kind:    client.ErrorKindTermsNotAccepted,
   224  		},
   225  	},
   226  	{
   227  		// No payment methods
   228  		input:    store.ErrNoPaymentMethods,
   229  		status:   400,
   230  		respType: daemon.ResponseTypeError,
   231  		response: &daemon.ErrorResult{
   232  			Message: "no payment methods",
   233  			Kind:    client.ErrorKindNoPaymentMethods,
   234  		},
   235  	},
   236  }
   237  
   238  func (s *buySuite) TestReadyToBuy(c *check.C) {
   239  	user := &auth.UserState{
   240  		Username: "username",
   241  		Email:    "email@test.com",
   242  	}
   243  
   244  	for _, test := range readyToBuyTests {
   245  		s.err = test.input
   246  
   247  		req, err := http.NewRequest("GET", "/v2/buy/ready", nil)
   248  		c.Assert(err, check.IsNil)
   249  
   250  		rsp := s.jsonReq(c, req, user)
   251  		c.Check(rsp.Status, check.Equals, test.status)
   252  		c.Check(rsp.Type, check.Equals, test.respType)
   253  		c.Assert(rsp.Result, check.FitsTypeOf, test.response)
   254  		c.Check(rsp.Result, check.DeepEquals, test.response)
   255  	}
   256  }