<commit_before>package api_test

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"

	prescriptionService "github.com/tidepool-org/platform/prescription/service"
	serviceTest "github.com/tidepool-org/platform/prescription/service/test"

	"github.com/ant0ine/go-json-rest/rest"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gstruct"
	"go.mongodb.org/mongo-driver/bson/primitive"

	authTest "github.com/tidepool-org/platform/auth/test"
	"github.com/tidepool-org/platform/prescription"
	"github.com/tidepool-org/platform/prescription/api"
	prescriptionTest "github.com/tidepool-org/platform/prescription/test"
	"github.com/tidepool-org/platform/request"
	"github.com/tidepool-org/platform/service"
	"github.com/tidepool-org/platform/user"

	"github.com/tidepool-org/platform/log"
	logTest "github.com/tidepool-org/platform/log/test"
	testRest "github.com/tidepool-org/platform/test/rest"
	userTest "github.com/tidepool-org/platform/user/test"
)

var _ = Describe("V1", func() {
	var userClient *userTest.Client
	var deviceSettingsValidator prescriptionService.DeviceSettingsValidator
	var prescriptionService *prescriptionTest.PrescriptionAccessor

	BeforeEach(func() {
		deviceSettingsValidator = serviceTest.NewNoopSettingsValidator()
		prescriptionService = prescriptionTest.NewPrescriptionAccessor()
		userClient = userTest.NewClient()
	})

	AfterEach(func() {
		prescriptionService.Expectations()
		userClient.AssertOutputsEmpty()
	})

	Context("NewRouter", func() {
		It("returns successfully", func() {
			Expect(api.NewRouter(api.Params{
				DeviceSettingsValidator: deviceSettingsValidator,
				PrescriptionService:     prescriptionService,
				UserClient:              userClient,
			})).ToNot(BeNil())
		})
	})

	Context("with new router", func() {
		var router service.Router

		BeforeEach(func() {
			router = api.NewRouter(api.Params{
				DeviceSettingsValidator: deviceSettingsValidator,
				PrescriptionService:     prescriptionService,
				UserClient:              userClient,
			})
			Expect(router).ToNot(BeNil())
		})

		Context("Routes", func() {
			It("returns the expected routes", func() {
				Expect(router.Routes()).To(ConsistOf(
					PointTo(MatchFields(IgnoreExtras, Fields{"HttpMethod": Equal(http.MethodPost), "PathExp": Equal("/v1/prescriptions")})),
					PointTo(MatchFields(IgnoreExtras, Fields{"HttpMethod": Equal(http.MethodGet), "PathExp": Equal("/v1/prescriptions")})),
					PointTo(MatchFields(IgnoreExtras, Fields{"HttpMethod": Equal(http.MethodGet), "PathExp": Equal("/v1/users/:userId/prescriptions")})),
					PointTo(MatchFields(IgnoreExtras, Fields{"HttpMethod": Equal(http.MethodPost), "PathExp": Equal("/v1/prescriptions/claim")})),
					PointTo(MatchFields(IgnoreExtras, Fields{"HttpMethod": Equal(http.MethodGet), "PathExp": Equal("/v1/prescriptions/:prescriptionId")})),
					PointTo(MatchFields(IgnoreExtras, Fields{"HttpMethod": Equal(http.MethodPatch), "PathExp": Equal("/v1/prescriptions/:prescriptionId")})),
					PointTo(MatchFields(IgnoreExtras, Fields{"HttpMethod": Equal(http.MethodDelete), "PathExp": Equal("/v1/prescriptions/:prescriptionId")})),
					PointTo(MatchFields(IgnoreExtras, Fields{"HttpMethod": Equal(http.MethodPost), "PathExp": Equal("/v1/prescriptions/:prescriptionId/revisions")})),
				))
			})
		})

		Context("with response and request", func() {
			var res *testRest.ResponseWriter
			var req *rest.Request
			var ctx context.Context
			var handlerFunc rest.HandlerFunc
			var details request.Details

			BeforeEach(func() {
				res = testRest.NewResponseWriter()
				res.HeaderOutput = &http.Header{}
				req = testRest.NewRequest()
				ctx = log.NewContextWithLogger(req.Context(), logTest.NewLogger())
				req.Request = req.WithContext(ctx)
			})

			JustBeforeEach(func() {
				app, err := rest.MakeRouter(router.Routes()...)
				Expect(err).ToNot(HaveOccurred())
				Expect(app).ToNot(BeNil())
				handlerFunc = app.AppFunc()
			})

			AfterEach(func() {
				res.AssertOutputsEmpty()
			})

			Context("with patient and clinician", func() {
				var patient *user.User
				var clinician *user.User

				BeforeEach(func() {
					patient = userTest.RandomUser()
					clinician = userTest.RandomUser()

					clinicianRoles := []string{user.RoleClinic}
					clinician.Roles = &clinicianRoles
				})

				When("signed in", func() {
					var currentUser *user.User
					asService := false

					JustBeforeEach(func() {
						if asService {
							details = request.NewDetails(request.MethodServiceSecret, "", authTest.NewServiceSecret())
						} else {
							details = request.NewDetails(request.MethodSessionToken, *currentUser.UserID, "")
						}
						if currentUser != nil {
							userClient.GetOutputs = []userTest.GetOutput{{User: currentUser, Error: nil}}
						}
						req.Request = req.WithContext(request.NewContextWithDetails(req.Context(), details))
					})

					JustAfterEach(func() {
						currentUser = nil
						asService = false
					})

					Context("create prescription", func() {
						var create *prescription.RevisionCreate
						var prescr *prescription.Prescription

						BeforeEach(func() {
							req.Method = http.MethodPost
							req.URL.Path = "/v1/prescriptions"

							create = prescriptionTest.RandomRevisionCreate()
							prescr = prescriptionTest.RandomPrescription()
							body, err := json.Marshal(create)
							Expect(err).ToNot(HaveOccurred())

							req.Body = ioutil.NopCloser(bytes.NewBuffer(body))
							res.WriteOutputs = []testRest.WriteOutput{{BytesWritten: 0, Error: nil}}
						})

						Context("as patient", func() {
							BeforeEach(func() {
								currentUser = patient
							})

							It("returns forbidden status code", func() {
								handlerFunc(res, req)
								Expect(res.WriteHeaderInputs).To(Equal([]int{http.StatusForbidden}))
								Expect(res.WriteInputs).To(HaveLen(1))
							})
						})

						Context("as clinician", func() {
							BeforeEach(func() {
								currentUser = clinician
							})

							It("returns created status code", func() {
								prescriptionService.CreatePrescriptionOutputs = []prescriptionTest.CreatePrescriptionOutput{{Prescription: prescr, Error: nil}}
								handlerFunc(res, req)
								Expect(res.WriteHeaderInputs).To(Equal([]int{http.StatusCreated}))
								Expect(res.WriteInputs).To(HaveLen(1))
							})
						})

						Context("as service", func() {
							BeforeEach(func() {
								asService = true
							})

							It("returns unauthorized status code", func() {
								handlerFunc(res, req)
								Expect(res.WriteHeaderInputs).To(Equal([]int{http.StatusUnauthorized}))
								Expect(res.WriteInputs).To(HaveLen(1))
							})
						})
					})
<commit_msg>Add failing test for prescription request payload validation<commit_after>package api_test

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"

	prescriptionService "github.com/tidepool-org/platform/prescription/service"
	serviceTest "github.com/tidepool-org/platform/prescription/service/test"

	"github.com/ant0ine/go-json-rest/rest"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gstruct"
	"go.mongodb.org/mongo-driver/bson/primitive"

	authTest "github.com/tidepool-org/platform/auth/test"
	"github.com/tidepool-org/platform/prescription"
	"github.com/tidepool-org/platform/prescription/api"
	prescriptionTest "github.com/tidepool-org/platform/prescription/test"
	"github.com/tidepool-org/platform/request"
	"github.com/tidepool-org/platform/service"
	"github.com/tidepool-org/platform/user"

	"github.com/tidepool-org/platform/log"
	logTest "github.com/tidepool-org/platform/log/test"
	testRest "github.com/tidepool-org/platform/test/rest"
	userTest "github.com/tidepool-org/platform/user/test"
)

var _ = Describe("V1", func() {
	var userClient *userTest.Client
	var deviceSettingsValidator prescriptionService.DeviceSettingsValidator
	var prescriptionService *prescriptionTest.PrescriptionAccessor

	BeforeEach(func() {
		deviceSettingsValidator = serviceTest.NewNoopSettingsValidator()
		prescriptionService = prescriptionTest.NewPrescriptionAccessor()
		userClient = userTest.NewClient()
	})

	AfterEach(func() {
		prescriptionService.Expectations()
		userClient.AssertOutputsEmpty()
	})

	Context("NewRouter", func() {
		It("returns successfully", func() {
			Expect(api.NewRouter(api.Params{
				DeviceSettingsValidator: deviceSettingsValidator,
				PrescriptionService:     prescriptionService,
				UserClient:              userClient,
			})).ToNot(BeNil())
		})
	})

	Context("with new router", func() {
		var router service.Router

		BeforeEach(func() {
			router = api.NewRouter(api.Params{
				DeviceSettingsValidator: deviceSettingsValidator,
				PrescriptionService:     prescriptionService,
				UserClient:              userClient,
			})
			Expect(router).ToNot(BeNil())
		})

		Context("Routes", func() {
			It("returns the expected routes", func() {
				Expect(router.Routes()).To(ConsistOf(
					PointTo(MatchFields(IgnoreExtras, Fields{"HttpMethod": Equal(http.MethodPost), "PathExp": Equal("/v1/prescriptions")})),
					PointTo(MatchFields(IgnoreExtras, Fields{"HttpMethod": Equal(http.MethodGet), "PathExp": Equal("/v1/prescriptions")})),
					PointTo(MatchFields(IgnoreExtras, Fields{"HttpMethod": Equal(http.MethodGet), "PathExp": Equal("/v1/users/:userId/prescriptions")})),
					PointTo(MatchFields(IgnoreExtras, Fields{"HttpMethod": Equal(http.MethodPost), "PathExp": Equal("/v1/prescriptions/claim")})),
					PointTo(MatchFields(IgnoreExtras, Fields{"HttpMethod": Equal(http.MethodGet), "PathExp": Equal("/v1/prescriptions/:prescriptionId")})),
					PointTo(MatchFields(IgnoreExtras, Fields{"HttpMethod": Equal(http.MethodPatch), "PathExp": Equal("/v1/prescriptions/:prescriptionId")})),
					PointTo(MatchFields(IgnoreExtras, Fields{"HttpMethod": Equal(http.MethodDelete), "PathExp": Equal("/v1/prescriptions/:prescriptionId")})),
					PointTo(MatchFields(IgnoreExtras, Fields{"HttpMethod": Equal(http.MethodPost), "PathExp": Equal("/v1/prescriptions/:prescriptionId/revisions")})),
				))
			})
		})

		Context("with response and request", func() {
			var res *testRest.ResponseWriter
			var req *rest.Request
			var ctx context.Context
			var handlerFunc rest.HandlerFunc
			var details request.Details

			BeforeEach(func() {
				res = testRest.NewResponseWriter()
				res.HeaderOutput = &http.Header{}
				req = testRest.NewRequest()
				ctx = log.NewContextWithLogger(req.Context(), logTest.NewLogger())
				req.Request = req.WithContext(ctx)
			})

			JustBeforeEach(func() {
				app, err := rest.MakeRouter(router.Routes()...)
				Expect(err).ToNot(HaveOccurred())
				Expect(app).ToNot(BeNil())
				handlerFunc = app.AppFunc()
			})

			AfterEach(func() {
				res.AssertOutputsEmpty()
			})

			Context("with patient and clinician", func() {
				var patient *user.User
				var clinician *user.User

				BeforeEach(func() {
					patient = userTest.RandomUser()
					clinician = userTest.RandomUser()

					clinicianRoles := []string{user.RoleClinic}
					clinician.Roles = &clinicianRoles
				})

				When("signed in", func() {
					var currentUser *user.User
					asService := false

					JustBeforeEach(func() {
						if asService {
							details = request.NewDetails(request.MethodServiceSecret, "", authTest.NewServiceSecret())
						} else {
							details = request.NewDetails(request.MethodSessionToken, *currentUser.UserID, "")
						}
						if currentUser != nil {
							userClient.GetOutputs = []userTest.GetOutput{{User: currentUser, Error: nil}}
						}
						req.Request = req.WithContext(request.NewContextWithDetails(req.Context(), details))
					})

					JustAfterEach(func() {
						currentUser = nil
						asService = false
					})

					Context("create prescription", func() {
						var create *prescription.RevisionCreate
						var prescr *prescription.Prescription

						BeforeEach(func() {
							req.Method = http.MethodPost
							req.URL.Path = "/v1/prescriptions"

							create = prescriptionTest.RandomRevisionCreate()
							prescr = prescriptionTest.RandomPrescription()
							body, err := json.Marshal(create)
							Expect(err).ToNot(HaveOccurred())

							req.Body = ioutil.NopCloser(bytes.NewBuffer(body))
							res.WriteOutputs = []testRest.WriteOutput{{BytesWritten: 0, Error: nil}}
						})

						Context("as patient", func() {
							BeforeEach(func() {
								currentUser = patient
							})

							It("returns forbidden status code", func() {
								handlerFunc(res, req)
								Expect(res.WriteHeaderInputs).To(Equal([]int{http.StatusForbidden}))
								Expect(res.WriteInputs).To(HaveLen(1))
							})
						})

						Context("as clinician", func() {
							BeforeEach(func() {
								currentUser = clinician
							})

							It("returns created status code", func() {
								prescriptionService.CreatePrescriptionOutputs = []prescriptionTest.CreatePrescriptionOutput{{Prescription: prescr, Error: nil}}
								handlerFunc(res, req)
								Expect(res.WriteHeaderInputs).To(Equal([]int{http.StatusCreated}))
								Expect(res.WriteInputs).To(HaveLen(1))
							})

							Context("with missing required attribute when state is 'submitted'", func() {
								BeforeEach(func() {
									create.PhoneNumber = nil
									body, err := json.Marshal(create)
									Expect(err).ToNot(HaveOccurred())

									req.Body = ioutil.NopCloser(bytes.NewBuffer(body))
								})

								It("returns bad request with validation error", func() {
									expectedErrorBody := "{\"code\":\"value-empty\",\"title\":\"value is empty\",\"detail\":\"value is empty\",\"source\":{\"pointer\":\"/phoneNumber\"}}\n"
									handlerFunc(res, req)
									Expect(res.WriteHeaderInputs).To(Equal([]int{http.StatusBadRequest}))
									Expect(res.WriteInputs).To(HaveLen(1))
									Expect(string(res.WriteInputs[0])).To(Equal(expectedErrorBody))
								})

							})
						})

						Context("as service", func() {
							BeforeEach(func() {
								asService = true
							})

							It("returns unauthorized status code", func() {
								handlerFunc(res, req)
								Expect(res.WriteHeaderInputs).To(Equal([]int{http.StatusUnauthorized}))
								Expect(res.WriteInputs).To(HaveLen(1))
							})
						})
					})

{'fraction_non_alphanumeric': 0.14151735722284434, 'fraction_numerical': 0.0022396416573348264, 'mean_word_length': 3.770951585976628, 'pattern_counts': {'":': 37, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1851465', 'n_tokens_mistral': 5583, 'n_tokens_neox': 4341, 'n_words': 661}