11const { expect } = require ( 'chai' ) ;
2+ const sinon = require ( 'sinon' ) ;
3+ const { Readable } = require ( 'stream' ) ;
4+ const { HttpClient } = require ( '@contentstack/cli-utilities' ) ;
25const GitHubClient = require ( '../lib/bootstrap/github/client' ) . default ;
6+ const GithubError = require ( '../lib/bootstrap/github/github-error' ) . default ;
37
48describe ( 'Github Client' , function ( ) {
59 it ( 'Parse github url' , ( ) => {
@@ -16,4 +20,124 @@ describe('Github Client', function () {
1620 'https://api.github.com/repos/contentstack/contentstack-nextjs-react-universal-demo/tarball/cli-use' ,
1721 ) ;
1822 } ) ;
23+
24+ describe ( 'streamRelease' , function ( ) {
25+ let sandbox ;
26+
27+ beforeEach ( ( ) => {
28+ sandbox = sinon . createSandbox ( ) ;
29+ } ) ;
30+
31+ afterEach ( ( ) => {
32+ sandbox . restore ( ) ;
33+ } ) ;
34+
35+ it ( 'should throw GithubError with status 404 when the branch does not exist' , async ( ) => {
36+ const notFoundStream = new Readable ( { read ( ) { } } ) ;
37+ notFoundStream . push ( Buffer . from ( '404: Not Found' ) ) ;
38+ notFoundStream . push ( null ) ;
39+
40+ const httpStub = { get : sandbox . stub ( ) . resolves ( { status : 404 , data : notFoundStream } ) , options : sandbox . stub ( ) . returnsThis ( ) } ;
41+ sandbox . stub ( HttpClient , 'create' ) . returns ( httpStub ) ;
42+
43+ const client = new GitHubClient ( GitHubClient . parsePath ( 'contentstack/kickstart-next' ) ) ;
44+
45+ try {
46+ await client . streamRelease ( client . gitTarBallUrl ) ;
47+ throw new Error ( 'Expected GithubError to be thrown' ) ;
48+ } catch ( err ) {
49+ expect ( err ) . to . be . instanceOf ( GithubError ) ;
50+ expect ( err . status ) . to . equal ( 404 ) ;
51+ }
52+ } ) ;
53+
54+ it ( 'should throw GithubError with status 500 on server error' , async ( ) => {
55+ const errStream = new Readable ( { read ( ) { } } ) ;
56+ errStream . push ( Buffer . from ( 'Internal Server Error' ) ) ;
57+ errStream . push ( null ) ;
58+
59+ const httpStub = { get : sandbox . stub ( ) . resolves ( { status : 500 , data : errStream } ) , options : sandbox . stub ( ) . returnsThis ( ) } ;
60+ sandbox . stub ( HttpClient , 'create' ) . returns ( httpStub ) ;
61+
62+ const client = new GitHubClient ( GitHubClient . parsePath ( 'contentstack/kickstart-next' ) ) ;
63+
64+ try {
65+ await client . streamRelease ( client . gitTarBallUrl ) ;
66+ throw new Error ( 'Expected GithubError to be thrown' ) ;
67+ } catch ( err ) {
68+ expect ( err ) . to . be . instanceOf ( GithubError ) ;
69+ expect ( err . status ) . to . equal ( 500 ) ;
70+ }
71+ } ) ;
72+
73+ it ( 'should throw GithubError with status 302 on unexpected redirect' , async ( ) => {
74+ const redirectStream = new Readable ( { read ( ) { } } ) ;
75+ redirectStream . push ( null ) ;
76+
77+ const httpStub = { get : sandbox . stub ( ) . resolves ( { status : 302 , data : redirectStream } ) , options : sandbox . stub ( ) . returnsThis ( ) } ;
78+ sandbox . stub ( HttpClient , 'create' ) . returns ( httpStub ) ;
79+
80+ const client = new GitHubClient ( GitHubClient . parsePath ( 'contentstack/kickstart-next' ) ) ;
81+
82+ try {
83+ await client . streamRelease ( client . gitTarBallUrl ) ;
84+ throw new Error ( 'Expected GithubError to be thrown' ) ;
85+ } catch ( err ) {
86+ expect ( err ) . to . be . instanceOf ( GithubError ) ;
87+ expect ( err . status ) . to . equal ( 302 ) ;
88+ }
89+ } ) ;
90+
91+ it ( 'should return the response stream when status is 200' , async ( ) => {
92+ const mockStream = new Readable ( { read ( ) { } } ) ;
93+ const httpStub = { get : sandbox . stub ( ) . resolves ( { status : 200 , data : mockStream } ) , options : sandbox . stub ( ) . returnsThis ( ) } ;
94+ sandbox . stub ( HttpClient , 'create' ) . returns ( httpStub ) ;
95+
96+ const client = new GitHubClient ( GitHubClient . parsePath ( 'contentstack/kickstart-next' ) ) ;
97+ const result = await client . streamRelease ( client . gitTarBallUrl ) ;
98+
99+ expect ( result ) . to . equal ( mockStream ) ;
100+ } ) ;
101+
102+ it ( 'should pass Authorization header for private repos' , async ( ) => {
103+ const mockStream = new Readable ( { read ( ) { } } ) ;
104+ const httpStub = { get : sandbox . stub ( ) . resolves ( { status : 200 , data : mockStream } ) , options : sandbox . stub ( ) . returnsThis ( ) } ;
105+ sandbox . stub ( HttpClient , 'create' ) . returns ( httpStub ) ;
106+
107+ const client = new GitHubClient ( GitHubClient . parsePath ( 'contentstack/private-repo' ) , true , 'my-token' ) ;
108+ await client . streamRelease ( client . gitTarBallUrl ) ;
109+
110+ const callOptions = httpStub . options . firstCall . args [ 0 ] ;
111+ expect ( callOptions . headers ) . to . deep . equal ( { Authorization : 'token my-token' } ) ;
112+ } ) ;
113+
114+ it ( 'should throw GithubError immediately for private repos with no access token' , async ( ) => {
115+ const client = new GitHubClient ( GitHubClient . parsePath ( 'contentstack/private-repo' ) , true , undefined ) ;
116+
117+ try {
118+ await client . streamRelease ( client . gitTarBallUrl ) ;
119+ throw new Error ( 'Expected GithubError to be thrown' ) ;
120+ } catch ( err ) {
121+ expect ( err ) . to . be . instanceOf ( GithubError ) ;
122+ expect ( err . status ) . to . equal ( 1 ) ;
123+ }
124+ } ) ;
125+ } ) ;
126+
127+ describe ( 'extract' , function ( ) {
128+ it ( 'should reject (not crash the process) when the stream contains invalid gzip data' , async ( ) => {
129+ const client = new GitHubClient ( GitHubClient . parsePath ( 'contentstack/kickstart-next' ) ) ;
130+
131+ const badStream = new Readable ( { read ( ) { } } ) ;
132+ badStream . push ( Buffer . from ( '404: Not Found' ) ) ;
133+ badStream . push ( null ) ;
134+
135+ try {
136+ await client . extract ( '/tmp' , badStream ) ;
137+ throw new Error ( 'Expected extraction error to be thrown' ) ;
138+ } catch ( err ) {
139+ expect ( err . code ) . to . equal ( 'Z_DATA_ERROR' ) ;
140+ }
141+ } ) ;
142+ } ) ;
19143} ) ;
0 commit comments